Skip to content

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 ClientContextSearchExecutor KeywordQuery.QueryText

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 AdministrationManaged Properties. Any crawled property can be promoted to a refinable managed property.


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.