Search — User Guide¶
Audience: End users, site administrators, and developers working with search in Cesivi.
See also: REST API reference · CSOM guide · Permissions guide
Overview¶
Cesivi ships a full-text search engine backed by Lucene. It supports:
- KQL (Keyword Query Language) — boolean operators, property queries, phrase search, wildcards, date ranges
- Security trimming — results are filtered to items the current user can read
- Multi-surface results — same query engine serves all URL shapes (Classic results page, Modern search, SharePoint-compat ASPX, REST, SOAP, CSOM)
- Refiners — faceted filtering by Author, ContentType, FileType, and custom managed properties
- Sub-web scoping — search can be scoped to a specific sub-site
Search Entry Points¶
Cesivi exposes search through six URL shapes. All hit the same Lucene index and produce the same trimmed results.
| Surface | URL | Query parameter |
|---|---|---|
| Classic Results page | /Search/Results |
?Query= |
| SharePoint-compat ASPX | /_layouts/15/osssearchresults.aspx |
?k= |
| Modern Search | /Modern/Search |
?Q= |
| REST (JSON) | /_api/search/query |
?querytext= |
| SOAP | /_vti_bin/search.asmx |
XML body |
| CSOM | ClientContext → SearchExecutor |
KeywordQuery.QueryText |
Top-nav search box¶
Every page has a search box in the top navigation bar. Type a query and press Enter — the browser navigates to /Search/Results?Query={your-query}.
KQL Query Syntax¶
Cesivi's search engine parses KQL (Keyword Query Language) — the same syntax used by SharePoint 2019 On-Premises.
Basic terms¶
| Query | What it matches |
|---|---|
budget |
Items containing the word "budget" |
budget review |
Items containing both "budget" AND "review" |
"budget review" |
Items containing the exact phrase "budget review" |
budget* |
Items containing words starting with "budget" |
Boolean operators¶
alpha AND beta -- must contain both words
alpha OR beta -- must contain at least one
alpha NOT beta -- contains alpha but not beta
alpha -beta -- same as NOT (minus-prefix shorthand)
Property queries¶
Title:budget -- Title field contains "budget"
Author:admin* -- Author field starts with "admin"
ContentType:Item -- matches by content type name
FileType:docx -- matches .docx files
Date range queries¶
Modified>=2024-01-01 -- modified on or after Jan 1 2024
Created>=2023-01-01 AND Created<2024-01-01 -- created in 2023
Combined queries¶
Title:KQL_Alpha AND Modified>=2020-01-01
Author:admin* NOT FileType:pdf
"quarterly report" FileType:docx
Refiners¶
When results are displayed in the Classic or Modern search surfaces, a refiners panel appears on the left side. Clicking a refiner narrows the result set by that facet.
Default refiners available:
- Author — who created the item
- ContentType — Item, Document, Folder, etc.
- FileType — docx, pdf, xlsx, etc. (for libraries)
- Modified — relative date buckets (Last 7 days, Last 30 days, etc.)
Refiner values are AND-ed: selecting Author=admin AND ContentType=Item returns items matching both filters.
Refiners are configured via Search Administration → Managed Properties. Any crawled property can be promoted to a refinable managed property.
Scope and Sub-Web Search¶
Site-wide vs. this-web scope¶
The Classic Results page has a Scope drop-down:
| Scope value | What is searched |
|---|---|
All (default) |
All content across the site collection |
ThisSite |
Current site and all sub-sites |
ThisWeb |
Current sub-site only |
People |
People / users directory |
URL: /Search/Results?Query=budget&Scope=ThisSite
Searching within a sub-web¶
Prefix the URL with the sub-web path:
/{subweb}/Search/Results?Query=budget
/{subweb}/_layouts/15/osssearchresults.aspx?k=budget
/{subweb}/Modern/Search?Q=budget
The server automatically scopes the query to items within /{subweb}.
REST API¶
Basic query¶
GET /_api/search/query?querytext='budget'
Authorization: Basic <base64>
Accept: application/json
With parameters¶
GET /_api/search/query?querytext='budget'&rowlimit=20&startrow=0&selectproperties='Title,Author,Path'
| Parameter | Default | Description |
|---|---|---|
querytext |
— | KQL query string (required) |
rowlimit |
10 | Max results per page |
startrow |
0 | Offset for pagination |
selectproperties |
all | Comma-separated managed properties to return |
sortlist |
relevance | Sort specification, e.g. 'Modified:descending' |
Response structure¶
{
"d": {
"query": {
"PrimaryQueryResult": {
"RelevantResults": {
"TotalRows": 42,
"RowCount": 10,
"Table": {
"Rows": {
"results": [
{ "Cells": { "results": [ { "Key": "Title", "Value": "..." }, ... ] } }
]
}
}
},
"RefinerResults": { ... }
}
}
}
}
Pagination example¶
GET /_api/search/query?querytext='*'&rowlimit=10&startrow=0 -- page 1
GET /_api/search/query?querytext='*'&rowlimit=10&startrow=10 -- page 2
GET /_api/search/query?querytext='*'&rowlimit=10&startrow=20 -- page 3
SOAP API¶
POST /_vti_bin/search.asmx
Content-Type: text/xml
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:s="urn:Microsoft.Search">
<soap:Body>
<s:QueryEx>
<s:queryXml><![CDATA[
<QueryPacket>
<Query>
<QueryText>budget review</QueryText>
</Query>
</QueryPacket>
]]></s:queryXml>
</s:QueryEx>
</soap:Body>
</soap:Envelope>
Both Query (returns XML DataSet) and QueryEx (returns XML string) operations are supported.
CSOM¶
Add a reference to Cesivi.Client.Search and use SearchExecutor + KeywordQuery:
using Cesivi.Client;
using Cesivi.Client.Search.Query;
using var ctx = new ClientContext("http://localhost:15010/Default/RootSite");
ctx.Credentials = new NetworkCredential("admin", "admin");
var executor = new SearchExecutor(ctx);
var kq = new KeywordQuery(ctx)
{
QueryText = "budget review",
RowLimit = 20,
Refiners = "Author,FileType",
TrimDuplicates = true,
};
// Optionally select specific managed properties:
// kq.SelectProperties.Add("Title");
// kq.SelectProperties.Add("Path");
var results = executor.ExecuteQuery(kq);
ctx.ExecuteQuery();
foreach (var table in results.Value)
{
if (table.TableType == "RelevantResults")
{
Console.WriteLine($"Total: {table.TotalRows}");
foreach (var row in table.ResultRows ?? [])
{
if (row.TryGetValue("Title", out var title))
Console.WriteLine($" {title}");
}
}
}
TrimDuplicates¶
TrimDuplicates |
Behaviour |
|---|---|
true (default) |
Near-duplicate results are collapsed into one |
false |
All results including near-duplicates are returned; TotalRowsIncludingDuplicates reflects the full count |
Security Trimming¶
Cesivi trims search results based on the permissions of the authenticated user. Items the current user cannot read are excluded from results — the trimming happens server-side before the response is sent.
- Users see only items in lists/libraries where they have at least Read permission
- Breaking permission inheritance on a list item (unique permissions) immediately removes that item from other users' search results
- Restoring inheritance makes the item visible again
Security trimming applies to all search surfaces: REST, SOAP, CSOM, and all WebUI URL shapes.
Search Administration¶
Navigate to Cesivi Administration → Search (or /_layouts/15/searchadmin.aspx) to configure:
| Section | What you can configure |
|---|---|
| Managed Properties | Create / edit crawled → managed property mappings; mark as refinable, sortable, retrievable, queryable |
| Result Sources | Named query scopes with pre-set filters and promoted results |
| Query Rules | Conditional result boosts, best-bet blocks, and promoted results based on query intent |
Zero-Results Handling¶
When a query produces no results, the results page shows a "No results found" message and suggests:
- Checking spelling
- Trying a broader query
- Removing refiners if active
The REST API returns TotalRows: 0 and an empty ResultRows array — not an error.
Troubleshooting¶
| Symptom | Likely cause | Fix |
|---|---|---|
| Item I created doesn't appear in search | Index crawler hasn't processed it yet | Wait a few seconds; the Lucene index updates asynchronously |
| Sub-web search returns root-web items | Scope not set to ThisWeb |
Add ?Scope=ThisWeb to the URL |
SOAP returns <faultcode> |
Query XML malformed | Check the <QueryText> element is present and well-formed |
| REST returns 401 | Missing or wrong credentials | Pass Authorization: Basic <base64(user:pass)> |
| Refiner panel empty | No items indexed yet or refinable MPs not configured | Seed data, wait for indexing, verify Managed Properties in Search Admin |
SearchExecutor throws ServerException |
CSOM client target URL wrong | Ensure ClientContext URL points to the site root, not a list or file URL |
API Compat Reference¶
| Feature | REST | SOAP | CSOM | WebUI |
|---|---|---|---|---|
| Basic keyword query | ✅ | ✅ | ✅ | ✅ |
| KQL boolean AND/OR/NOT | ✅ | ✅ | ✅ | ✅ |
Property query (Title:x) |
✅ | ✅ | ✅ | ✅ |
| Phrase search | ✅ | ✅ | ✅ | ✅ |
| Date range | ✅ | ✅ | ✅ | ✅ |
| FileType filter | ✅ | ✅ | ✅ | ✅ |
| Refiners | ✅ | ✅ | ✅ | ✅ |
| Pagination | ✅ | ✅ | ✅ | ✅ |
| Security trimming | ✅ | ✅ | ✅ | ✅ |
| Sub-web scope | ✅ | ✅ | ✅ | ✅ |
| TrimDuplicates toggle | ✅ | — | ✅ | — |
| Query suggestions | ✅ | ✅ | ✅ | ✅ |
| Promoted results / best bets | ✅ | ✅ | ✅ | ✅ |
Accessibility (WCAG 2.1 AA)¶
All search surfaces in Cesivi meet WCAG 2.1 AA as of v1.4 (PLAN-1645).
Search UI landmarks and semantics¶
| Surface | Landmark | Notes |
|---|---|---|
| Top navigation search box | <div role="search"> |
Visible on every page; <label> for input is visually hidden |
/Modern/Search |
<form role="search"> |
Both home and results forms use the landmark |
/Search/Results |
<form role="search"> |
Applies to the empty-state form |
/_layouts/15/Osssearchresults.aspx |
<input aria-label="Search"> |
Input is self-labeled |
| All refiner groups | <fieldset>/<legend> |
Replaces generic divs — screen readers announce group name |
| Search results list | <ol aria-label="Search results"> |
List count announced; each result is a <li> |
| Pagination | <nav aria-label="Search results pagination"> |
Navigation landmark |
| Admin modals (mp/rs/rt/dt/qr) | role="dialog" aria-modal="true" aria-labelledby |
Modal name announced on open |
Keyboard navigation¶
All search surfaces are keyboard-navigable:
- Tab moves through all interactive elements in DOM order
- Enter submits the search form from the query input
- Escape closes open Bootstrap modals
- Refiner checkboxes, scope/sort selects, and pagination links are all Tab-reachable
- Admin table buttons (#btnNewProperty, #btnNewSource, #btnNewRule) are focusable
Screen reader support¶
Screen-reader tested (proxy semantic verification) via axe-core + DOM inspection:
- All table headers use scope="col" — column names announced per cell
- All form labels use for= attribute — inputs announce with their label
- Results list structure: list count + individual item structure announced
- Search landmark (role="search") present on all search-bearing forms
axe-core gate¶
KnownAxeAcceptances = [] — zero waivers. Automated gate in SearchA11yTests.cs runs on
every CI build. Routes: 12 URL variants covering all search surfaces.