Skip to content

Commit 7867866

Browse files
committed
Add Custom Sort and Search Rules docs
Introduce two new documentation sections to docs-turing/semantic-navigation.md: Custom Sort and Search Rules. Custom Sort covers creating named, multi-level sorts (UI steps, behavior, built-in options, API endpoint /api/sn/{siteId}/custom-sort and related routes) and how the query builder applies sort levels. Search Rules documents rule structure (details, conditions, actions), evaluation semantics (first-match, grouping logic), supported parameters/operators/actions, examples, evaluation pipeline, and REST API endpoints for managing rules. Includes examples and SDK/response formats for integrating sort options and rule-driven behavior in the search UI.
1 parent 9c320c8 commit 7867866

1 file changed

Lines changed: 216 additions & 0 deletions

File tree

docs-turing/semantic-navigation.md

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -730,6 +730,222 @@ Spotlights operate in two modes:
730730

731731
---
732732

733+
<div className="page-break" />
734+
735+
### Custom Sort
736+
737+
Custom Sort allows administrators to define named, multi-level sort options beyond the built-in "relevance", "newest", and "oldest". Each custom sort consists of one or more sort levels (field + direction), applied in priority order to the Solr query.
738+
739+
#### Creating a Custom Sort
740+
741+
1. Navigate to the SN site's **Custom Sort** tab
742+
2. Click **New**
743+
3. Fill in the **Name** (used as the sort identifier in API requests) and optional **Description**
744+
4. Add one or more **Sort Levels**:
745+
746+
| Setting | Description |
747+
|---|---|
748+
| **Field** | The Solr field to sort by (selected from the site's configured fields) |
749+
| **Direction** | `ASC` (ascending) or `DESC` (descending) |
750+
| **Position** | Priority order — position 0 is the primary sort, position 1 is the first tiebreaker, and so on |
751+
752+
Use the move up/down buttons to reorder levels.
753+
754+
#### How It Works
755+
756+
When a search request includes `sort={customSortName}`, the query builder looks up the custom sort by name and applies each level to the Solr query in position order:
757+
758+
```
759+
# Custom sort "price_then_date" with two levels:
760+
# Position 0: price ASC
761+
# Position 1: date DESC
762+
#
763+
# Solr query: sort=price asc, date desc
764+
```
765+
766+
#### Built-in Sort Options
767+
768+
These are always available alongside any custom sorts:
769+
770+
| Value | Behavior |
771+
|---|---|
772+
| `relevance` | Default Solr relevance scoring (no explicit sort) |
773+
| `newest` | Sorts by the site's default date field, descending |
774+
| `oldest` | Sorts by the site's default date field, ascending |
775+
776+
#### Sort Options API
777+
778+
The endpoint `GET /api/sn/{siteName}/search/sort-options` returns all available sort options — built-in and custom — as a list of `{value, label}` pairs. This is consumed by the [React SDK's `useTuringSortOptions`](./react-sdk.md#useturingsortoptions) hook to populate sort dropdowns in the search UI.
779+
780+
```json
781+
[
782+
{ "value": "relevance", "label": "Relevance" },
783+
{ "value": "newest", "label": "Newest" },
784+
{ "value": "oldest", "label": "Oldest" },
785+
{ "value": "price_asc", "label": "Price: Low to High" },
786+
{ "value": "title_sort", "label": "Title A–Z" }
787+
]
788+
```
789+
790+
#### REST API
791+
792+
| Method | Endpoint | Description |
793+
|---|---|---|
794+
| `GET` | `/api/sn/{siteId}/custom-sort` | List all custom sorts |
795+
| `GET` | `/api/sn/{siteId}/custom-sort/{id}` | Get a custom sort with its levels |
796+
| `GET` | `/api/sn/{siteId}/custom-sort/fields` | List available fields for sorting |
797+
| `POST` | `/api/sn/{siteId}/custom-sort` | Create a new custom sort |
798+
| `PUT` | `/api/sn/{siteId}/custom-sort/{id}` | Update a custom sort |
799+
| `DELETE` | `/api/sn/{siteId}/custom-sort/{id}` | Delete a custom sort |
800+
801+
---
802+
803+
<div className="page-break" />
804+
805+
### Search Rules
806+
807+
Search Rules are a powerful automation mechanism that dynamically modifies search behavior based on conditions evaluated at query time. When a rule's conditions match the incoming search request, its actions are applied to the Solr query — overriding sort, adding filters, changing facets, or boosting results — all without any client-side logic.
808+
809+
Rules use **first-match semantics**: they are evaluated in position order, and only the first matching rule's actions are applied.
810+
811+
#### Rule Structure
812+
813+
Each rule has three parts:
814+
815+
| Part | Description |
816+
|---|---|
817+
| **Details** | Name, description, position (priority), and enabled/disabled toggle |
818+
| **Conditions** | One or more conditions grouped by parameter — all groups must match (AND between groups) |
819+
| **Actions** | One or more actions applied when the rule matches |
820+
821+
#### Conditions
822+
823+
Conditions define **when** a rule triggers. Each condition evaluates a search parameter against a value using an operator.
824+
825+
##### Parameters
826+
827+
| Parameter | Description | Example |
828+
|---|---|---|
829+
| `QUERY` | The user's search query (`q` parameter) | User searched for "education" |
830+
| `FILTER_QUERY` | Active facet filters (`fq` parameter) | User filtered by `category:books` |
831+
| `SORT` | Current sort specification | Sort is "newest" |
832+
| `LOCALE` | Current locale | Locale is `pt_BR` |
833+
834+
##### Operators
835+
836+
| Operator | Description |
837+
|---|---|
838+
| `EQUALS` | Exact match |
839+
| `CONTAINS` | Value contains the substring |
840+
| `STARTS_WITH` | Value starts with the substring |
841+
| `MATCHES_ANY` | Value contains the substring (alias for CONTAINS) |
842+
| `IS_EMPTY` | Parameter has no value |
843+
844+
##### Condition Grouping
845+
846+
Conditions are grouped by parameter. Within a group, conditions are combined using the **logic operator** (`AND` or `OR`). Between different parameter groups, `AND` is always used.
847+
848+
```
849+
Example: "When query contains 'laptop' OR 'notebook', AND locale is pt_BR"
850+
851+
Condition Group 1 (QUERY, OR):
852+
- QUERY CONTAINS "laptop"
853+
- QUERY CONTAINS "notebook"
854+
855+
Condition Group 2 (LOCALE):
856+
- LOCALE EQUALS "pt_BR"
857+
858+
Evaluation: (Group 1 OR) AND (Group 2) → both groups must match
859+
```
860+
861+
:::note
862+
`SORT` and `LOCALE` parameters always use OR logic internally, regardless of the configured logic operator.
863+
:::
864+
865+
#### Actions
866+
867+
Actions define **what happens** when the rule matches. Multiple actions can be applied by a single rule.
868+
869+
| Action | Description | Value format |
870+
|---|---|---|
871+
| `SET_SORT` | Override the sort order | Sort name (e.g., `newest`, custom sort name, or `field:direction`) |
872+
| `SET_ROWS` | Change the number of results per page | Integer (e.g., `20`) |
873+
| `ADD_FACETS` | Add facets to the response | Comma-separated field names (e.g., `brand,color`) |
874+
| `REMOVE_FACETS` | Hide facets from the response | Comma-separated facet names |
875+
| `ADD_FILTER_QUERY` | Automatically apply a filter | Filter expression (e.g., `type:article`) |
876+
| `SET_BOOST_QUERY` | Boost specific documents | Boost expression (e.g., `featured:true^10`) |
877+
878+
:::tip SET_SORT and SET_ROWS are single-use
879+
Each rule can have at most one `SET_SORT` and one `SET_ROWS` action. The UI prevents adding duplicates.
880+
:::
881+
882+
#### Evaluation Pipeline
883+
884+
```mermaid
885+
%%{init: {'theme': 'base', 'themeVariables': {'fontSize': '13px'}}}%%
886+
flowchart TD
887+
A[Search request arrives] --> B[Load enabled rules ordered by position]
888+
B --> C{Evaluate rule N}
889+
C -->|All condition groups match| D[Apply rule's actions]
890+
D --> E[Build Solr query with modified parameters]
891+
C -->|Not all groups match| F{More rules?}
892+
F -->|Yes| C
893+
F -->|No| E
894+
```
895+
896+
Rules are evaluated **before** the Solr query is built, allowing them to modify sort, facets, filters, and boost queries before they are sent to the search engine.
897+
898+
#### Examples
899+
900+
##### Example 1 — Force sort for product queries
901+
902+
When the user searches for "cheap" or "affordable", sort by price ascending:
903+
904+
| Part | Configuration |
905+
|---|---|
906+
| **Condition** | QUERY CONTAINS "cheap" OR QUERY CONTAINS "affordable" |
907+
| **Action** | SET_SORT → `price_asc` (a custom sort) |
908+
909+
##### Example 2 — Add filters for a specific locale
910+
911+
When the locale is `pt_BR`, automatically filter to Portuguese content:
912+
913+
| Part | Configuration |
914+
|---|---|
915+
| **Condition** | LOCALE EQUALS "pt_BR" |
916+
| **Action** | ADD_FILTER_QUERY → `language:pt` |
917+
918+
##### Example 3 — Boost featured content and limit results
919+
920+
When the query is empty (wildcard search), boost featured content and show fewer results:
921+
922+
| Part | Configuration |
923+
|---|---|
924+
| **Condition** | QUERY IS_EMPTY |
925+
| **Actions** | SET_BOOST_QUERY → `featured:true^10`, SET_ROWS → `5` |
926+
927+
##### Example 4 — Show specific facets for filtered searches
928+
929+
When the user filters by `category:electronics`, add brand and price facets:
930+
931+
| Part | Configuration |
932+
|---|---|
933+
| **Condition** | FILTER_QUERY EQUALS `category:electronics` |
934+
| **Action** | ADD_FACETS → `brand,price_range` |
935+
936+
#### REST API
937+
938+
| Method | Endpoint | Description |
939+
|---|---|---|
940+
| `GET` | `/api/sn/{siteId}/search-rule` | List all rules (ordered by position) |
941+
| `GET` | `/api/sn/{siteId}/search-rule/{id}` | Get a rule with conditions and actions |
942+
| `GET` | `/api/sn/{siteId}/search-rule/fields` | List available fields for conditions |
943+
| `POST` | `/api/sn/{siteId}/search-rule` | Create a new rule |
944+
| `PUT` | `/api/sn/{siteId}/search-rule/{id}` | Update a rule |
945+
| `DELETE` | `/api/sn/{siteId}/search-rule/{id}` | Delete a rule |
946+
947+
---
948+
733949
### Top Search Terms
734950

735951
Displays reports of the most frequently searched terms for this site. Turing ES records every search query and aggregates statistics across four time windows:

0 commit comments

Comments
 (0)