Content Advanced Search

Content Advanced Search is a simplified query language for searching articles and pages. It provides a clean, intuitive syntax that abstracts away backend complexities and focuses on common search use cases. This document and it's children explain how to use implement this, to meet the specific search requirements of your project.

Quick start

All Content Advanced Search queries follow this structure:

{
  "_id": "<request-identifier>",
  "language": {
    "primary": "<language-code>",
    "fallback": ["<language-code>", ...],
    "default": <boolean>
  },
  "query": {
    "<operator>": {
      // operator-specific parameters
    },
    "score": <score-options>
  },
  "page": <number>,
  "size": <number>,
  "sort": [<sort-options>],
  "explain": <boolean>
}

Core fields:

FieldDescriptionRequired?Default
_idClient-provided identifier echoed back in the response for request correlation (useful for multi-search)NoNone
languageLanguage filter with optional fallback languages (top-level operator)NoAll languages
queryThe search query (operator is optional - if omitted, all documents are matched).NoMatch all
pagePage number for paginationNo1
sizeResults per pageNo20
sortArray of sort criteriaNoRelevance score
explainEnable explain mode for diagnostic informationNofalse

Core concepts

Complete reference of all searchable fields, their data types, and supported operators. Includes top-level fields, hero media, author, content, categories, linked IDs, and sponsors.

Learn how to specify which fields to search using the path parameter. Supports single fields, nested fields, multiple fields, and wildcards.

Example:

{
  "path": "heroMedia.title"
}

Understand the supported data types (text, keyword, number, boolean, date, null) and their value formats. Includes date math syntax for relative date queries like now-30d.

Example:

{
  "range": {
    "path": "publishDate",
    "gte": "now-30d"
  }
}

Query operators

Operators define the type of search or filter to apply to your query.

Perform full-text search on articles using tokenisation and analysis. Ideal for natural language queries and word-based searches.

Example:

{
  "query": {
    "text": {
      "query": "cup final",
      "path": ["heroMedia.title", "content.text"]
    }
  }
}

Find articles and pages where words appear in an exact sequence. Unlike text, the word order must match.

Example:

{
  "query": {
    "phrase": {
      "query": "Team A FC",
      "path": "heroMedia.title"
    }
  }
}

Find articles and pages where a field exactly matches a given value. Supports Booleans, keywords, numbers, dates, and null values.

Example:

{
  "query": {
    "equal": {
      "path": "categories.id",
      "value": "5a3c1e8b-4f2d-4a1c-9b8e-1234567890ab"
    }
  }
}

Match articles and pages where a field contains any value from a specified list.

Example:

{
  "query": {
    "in": {
      "path": "tags",
      "values": ["breaking-news", "exclusive", "featured"]
    }
  }
}

Find articles where a field value falls within a specified range. Works with numbers, dates, and keyword fields.

Example:

{
  "query": {
    "range": {
      "path": "publishDate",
      "gte": "now-30d"
    }
  }
}

Match articles where a field value starts with a specified prefix. Perfect for autocomplete functionality.

Example:

{
  "query": {
    "prefix": {
      "query": "break",
      "path": "tags"
    }
  }
}

Write complex queries in a compact string format with field-specific searches, Boolean operators (AND, OR, NOT), and wildcards.

Example:

{
  "query": {
    "queryString": {
      "query": "heroMedia.title:championship AND publishDate:[now-7d TO now]",
      "defaultPath": "content.text"
    }
  }
}

Combine multiple query clauses using Boolean logic with must, should, mustNot, and filter.

Example:

{
  "query": {
    "compound": {
      "must": [
        {
          "text": {
            "query": "team a",
            "path": "heroMedia.title"
          }
        }
      ],
      "filter": [
        {
          "range": {
            "path": "publishDate",
            "gte": "now-7d"
          }
        }
      ]
    }
  }
}

Find articles and pages where a specified field exists and has a non-null value.

Example:

{
  "query": {
    "exists": {
      "path": "heroMedia"
    }
  }
}

Query nested objects within articles and pages, ensuring conditions apply to the same nested object.

Example:

{
  "query": {
    "nested": {
      "path": "linkedIds",
      "query": {
        "compound": {
          "must": [
            {
              "equal": {
                "path": "linkedIds.sourceSystem",
                "value": "OPTA_FOOTBALL_TEAM"
              }
            },
            {
              "equal": {
                "path": "linkedIds.sourceSystemId",
                "value": "t100"
              }
            }
          ]
        }
      }
    }
  }
}

Top-level operators

These operators must be used at the same level as the query field and cannot be nested within other operators.

Filter articles and pages by language with optional fallback languages. Essential for multi-lingual websites where content may not be available in all languages.

Example:

{
  "language": {
    "primary": "en",
    "fallback": ["es", "de"]
  },
  "query": {
    "text": {
      "query": "championship",
      "path": "heroMedia.title"
    }
  }
}

Response Format

Each search in the stream returns a response following the standard API response structure:

{
  "_id": "<request-identifier>",
  "status": "success" | "error",
  "errors": [
    {
      "code": "<error-code>",
      "message": "<error-message>",
      "path": "<json-path>"
    }
  ],
  "data": [...],
  "metadata": {
    "createdAt": "<timestamp>",
    "pageItems": <number>,
    "totalItems": <number>,
    "totalPages": <number>,
    "pageNumber": <number>,
    "pageSize": <number>,
    "sort": "<sort-description>"
  }
}

Example: Successful response:

{
  "_id": "featured",
  "status": "success",
  "data": [
    {"id": "article-1", "heroMedia": {"title": "Championship Final"}, ...},
    {"id": "article-2", "heroMedia": {"title": "Cup Results"}, ...}
  ],
  "metadata": {
    "createdAt": "2025-01-15T10:30:00Z",
    "pageItems": 2,
    "totalItems": 15,
    "totalPages": 5,
    "pageNumber": 1,
    "pageSize": 3,
    "sort": "publishDate:desc"
  }
}

Error handling

When errors occur, the response includes an errors array. Each error object contains:

FieldDescription
codeMachine-readable error code
messageHuman-readable error description
pathJSON path to the problematic field in the request

Multiple errors can be returned for a single request, allowing the query to execute while reporting issues encountered.

Example: Error response:

{
  "_id": "my-search",
  "status": "error",
  "errors": [
    {
      "code": "unknown_field",
      "message": "The field \"title\" is not recognised.",
      "path": "query.text.path"
    }
  ],
  "metadata": {
    "createdAt": "2025-01-15T10:30:00Z"
  }
}

Example: Query executed with warnings:

Queries may still execute and return results alongside errors:

{
  "_id": "search-with-issues",
  "status": "success",
  "data": [...],
  "errors": [
    {
      "code": "unknown_field",
      "message": "The field \"summary\" is not recognised.",
      "path": "query.compound.should[1].text.path"
    }
  ],
  "metadata": {
    "createdAt": "2025-01-15T10:30:00Z",
    "pageItems": 5,
    "totalItems": 42,
    "totalPages": 9,
    "pageNumber": 1,
    "pageSize": 5,
    "sort": "publishDate:desc"
  }
}

Example: Query with invalid field:

If you query a field that doesn't exist:

{
  "_id": "search-1",
  "query": { "text": { "query": "championship", "path": "title" } }
}

Response:

{
  "_id": "search-1",
  "status": "error",
  "errors": [
    {
      "code": "unknown_field",
      "message": "The field \"title\" is not recognised.",
      "path": "query.text.path"
    }
  ],
  "metadata": {
    "createdAt": "2025-01-15T10:30:00Z"
  }
}

Common error codes:

CodeDescription
unknown_fieldThe referenced field path does not exist in the schema
ambiguous_fieldThe field path resolves to more than one distinct field alias (e.g. in sort)
invalid_valueThe value is structurally invalid for its context (e.g. an unrecognised metric)
value_type_mismatchThe supplied value type is incompatible with the target field type
path_requiredThe operator was given an empty path list
no_compatible_fieldsAll resolved field paths were filtered out; none are compatible with the operator
multiple_fields_not_supportedThe operator requires a single field path but the path resolved to more than one
field_type_incompatibleThe resolved field type cannot be used with the requested operator
invalid_expressionA score function expression was nil or empty
unsupported_score_metricThe score reference names a metric that is not supported
gauss_decay_invalidThe gauss decay value is outside the valid (0, 1) range
values_requiredThe operator requires at least one value but was given an empty list
query_requiredThe operator requires a non-empty query string but was given an empty one
minimum_should_match_negativeThe compound operator minimumShouldMatch value is negative
validation_errorGeneric request validation failure
internal_errorUnexpected internal error

Notes:

  • Each JSON object in the stream is processed independently with its own results
  • Each search must include its own language filter if needed
  • Each search can have its own query, page, size, and sort options
  • Results are returned as separate JSON objects in the response stream (one per search)
  • Responses may arrive in a different order than requests due to parallel processing - use the _id field to correlate
  • Invalid JSON objects in the stream are skipped, and processing continues with the next object
  • For combining queries with Boolean logic in a single result set, use the compound operator instead

Search options

Control how articles are scored and ranked in search results using:

OptionDescription
boostMultiply the score by a factor
constantReplace the score with a fixed value
functionApply complex scoring functions

Example:

{
  "query": {
    "equal": {
      "path": "tags",
      "value": "breaking-news",
      "score": {
        "boost": 2.0
      }
    }
  }
}

Control result pagination and sort order as part of your Content Advanced Search query structure.

Pagination:

  • Use page and size fields in your query
  • Default: 20 results per page

Sorting:

  • Sort by one or more fields (dates, Booleans, keywords, numeric)
  • Default: relevance score (descending) when search query is present

Example:

{
  "query": {
    "text": {
      "query": "championship",
      "path": "heroMedia.title"
    }
  },
  "page": 2,
  "size": 20,
  "sort": [
    {
      "field": "publishDate",
      "order": "desc"
    }
  ]
}

Enable explain mode to receive diagnostic information about query execution, including scoring details, logical structure, and performance cost estimates.

Enable with: "explain": true in query structure

Explain fields:

FieldDescription
_scoreFinal relevance score for each result
_explain.maxScoreMaximum possible score (for normalisation)
_explain.logicBoolean logic structure of your query
_explain.costPerformance cost breakdown

Example:

{
  "_id": "explain-example",
  "data": [
    {
      "_score": 10.5,
      "id": "article-123"
      ...
    }
  ],
  "_explain": {
    "maxScore": 12.5,
    "logic": "heroMedia.title:championship AND publishDate:[now-30d TO now]",
    "cost": {
      "total": 165,
      "breakdown": {
        "operators": 60,
        "fields": 40,
        "boosts": 10,
        "functions": 0
      }
    }
  }
}

Use explain mode to:

  • Optimise query performance
  • Tune scoring and boosts
  • Validate query logic
  • Troubleshoot unexpected results

Additional resources

Learn recommended patterns for efficient, secure, and maintainable queries.

Optimise query performance with tips on field selection, query structure, and monitoring techniques.

Common Use Cases

Find pinned articles

{
  "query": {
    "equal": {
      "path": "pinned",
      "value": true
    }
  }
}

Search by category

{
  "query": {
    "nested": {
      "path": "categories",
      "query": {
        "equal": {
          "path": "categories.id",
          "value": "5a3c1e8b-4f2d-4a1c-9b8e-1234567890ab"
        }
      }
    }
  }
}

Multi-lingual content with fallback

Search for articles and pages in English with Spanish fallback:

{
  "language": {
    "primary": "en",
    "fallback": ["es"]
  },
  "query": {
    "text": {
      "query": "championship",
      "path": "heroMedia.title"
    }
  }
}

Boost recent articles

Match all articles and pages and apply time-based scoring:

{
  "query": {
    "score": {
      "function": {
        "gauss": {
          "field": "publishDate",
          "origin": "now",
          "scale": "30d",
          "decay": 0.5
        }
      }
    }
  }
}

Note: When no operator is specified, all documents are matched and the score function is applied.