Generated banner for Elasticsearch Search Relevance
Generated logo for Elasticsearch Search Relevance

Elasticsearch Search Relevance

ElasticOfficialCreated by elastic

  • Skill
  • Tool integration
  • Software development
  • Apache-2.0
  • No issues found

From the author

Improve Elasticsearch search relevance for content and catalog indices: pin or promote results with query rules (correct rule type, criteria, and rule-query wiring) and tune organic ranking with multi_match, field boosts, and analysis grounded in the index mapping. Use when search results rank poorly, a specific document must appear first for a query, or the user asks to tune full-text matching — not for ES|QL analytics, index ingest, or cluster health.
— the description by elastic

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

This skill provides a structured process for improving full-text search relevance in Elasticsearch indices. It distinguishes between deterministic merchandising (pinning specific documents) and organic ranking improvements. Users are guided to diagnose index mappings, select the appropriate relevance lever—either query rules for pinning or multi-match queries with field boosts for organic ranking—and verify results through side-by-side testing. The skill emphasizes using the elastic CLI for all operations and strictly avoiding anti-patterns like sorting by price or keyword fields to manipulate search relevance.

What it does

  • Diagnoses search relevance issues by inspecting index mappings and current query structures.
  • Implements deterministic document pinning using Elasticsearch query rules.
  • Tunes organic search ranking via multi-match queries with strategic field boosting.
  • Provides a testing framework to compare baseline and candidate search results.
  • Maps HTTP-shorthand operations to the required elastic CLI commands.
  • Validates rule criteria and search query wiring to ensure relevance levers function as expected.

When to use it

  • When specific documents must appear at the top of search results for a given query.
  • When search results for content or catalog indices are generally weak or irrelevant.
  • When you need to improve recall for multi-word user queries.
  • When you need to transition from fragile sorting hacks to robust relevance tuning.

Advantages

  • Ensures predictable search behavior for merchandising through query rules.
  • Promotes evidence-based tuning by requiring side-by-side top-hit comparisons.
  • Prevents common anti-patterns like using keyword fields for full-text search.
  • Standardizes the use of the elastic CLI for consistent environment interaction.

Usage examples

“I need to make sure the product with ID SKU123 always appears first when users search for 'sale'.”
The agent will create a pinned query rule for the 'sale' query string and provide the search body using the rule query to ensure SKU123 is promoted.
“My search results for 'running shoes' are poor; they only match the description field.”
The agent will analyze the index mapping, propose a multi_match query that boosts the title field, and guide you through testing the new ranking.

Install

  1. Download the skill as a ZIP:

    https://mp-staging.autogineer.com/agent-skills/elastic/elasticsearch-search-relevance/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip elasticsearch-search-relevance.zip -d .agents/skills

Documentation by elastic

Elasticsearch Search Relevance

Improve full-text search results on content and catalog indices. Diagnose the mapping and current query, choose the right relevance lever (query rules for deterministic pinning vs multi_match and field boosts for organic ranking), apply the change, and verify top hits before reporting success.

<!-- begin-partial: preamble -->

Environment Configuration

This skill executes Elasticsearch operations through the elastic CLI. If the elastic CLI is not installed, tell the user what it is needed for. Do not guess credentials, call the HTTP API directly, or attempt other workarounds.

This skill references operations in HTTP-shorthand form (e.g., GET /, GET /_cat/indices, GET /{index}/_mapping, GET /{index}/_settings/index.mode, POST /_query). The Operations table at the end of this document maps each shorthand to the equivalent elastic CLI command — always use the CLI rather than calling the HTTP API directly.

<!-- end-partial: preamble -->

Scope

This skill covers Query DSL relevance on indices with text (and optional keyword) fields — product catalogs, documentation, knowledge bases. It uses POST /{index}/_search for evaluation and query-rules APIs for pinned or excluded documents.

Out of scope:

  • ES|QL search (POST /_query) — use the elasticsearch-esql skill.

  • Semantic / vector / hybrid retrieval — different field types and retrievers.

  • Sorting by price, date, or popularity instead of fixing text relevance unless the user explicitly wants non-relevance ordering.

Relevance levers

User intentLeverAPIs
Always show document X first for query QQuery rules — pinned rule + rule query in searchPUT /_query_rules/{ruleset_id}, POST /{index}/_search
Hide specific documents for query QQuery rules — exclude rule + rule querySame
Better ranking for open-ended text queriesmulti_match across mapped text fields with field boostsPOST /{index}/_search
Tokens not matching user languageOperator, minimum_should_match, or synonym analyzersPOST /{index}/_search, optionally POST /{index}/_analyze

Decision rule: If the user names a document that must rank first for a specific query, use query rules. If results are generally weak for a phrase, tune the organic query from the mapping. Do not simulate pinning with extreme boosts, function_score, or sort clauses.

Process

  1. Inspect the mapping and current query. Call GET / to confirm connectivity. When the index is unknown, narrow candidates with GET /_cat/indices, then call GET /{index}/_mapping.

    From the mapping, list every text field (e.g., title, description) and every keyword field used for filters (brand, category). Note which fields are short (precision) vs long (recall). Read the user's current search body if provided — identify which fields it queries and whether it already uses rule, multi_match, or single-field match.

    Decision: Is the problem deterministic promotion (one doc must win for one query) or organic ranking (several docs should score better)? Data needed: index name, mapping properties, current query JSON, example query strings, and target document ID(s) when pinning.

  2. Choose the relevance lever. Apply the decision from step 1:

    • Pinning / promotion → Create a query-rules ruleset with a rule of type pinned (never exclude for promotion). Set criteria so the rule fires only for the intended query text — e.g., contains or exact on a metadata key such as query_string with value "sale". Set actions to pin the correct document via ids (e.g., ["SKU123"]) or docs (e.g., [{"_index":"catalog","_id":"SKU123"}]). Use docs when _id may not be unique across indices. Read Query Rules Reference for full structure.

    • Organic ranking → Replace single-field match on a long field with multi_match across the mapped text fields. Boost short fields (typically title^2 with description unboosted). Consider operator, minimum_should_match, or synonym-aware analyzers when multi-word recall is still poor — but do not sort by price, date, or keyword fields to fake better text relevance, and do not query .keyword sub-fields with term for analyzed user phrases. Read Multi-Match Tuning.

    Decision: Pick exactly one primary lever per request. Data needed: chosen fields and boosts, ruleset ID and rule ID names, criteria metadata keys, and pinned document identifiers.

  3. Apply the change. Execute the APIs for the chosen lever:

    Query rules path

    • Create or replace the ruleset with PUT /_query_rules/{ruleset_id} (or add one rule with PUT /_query_rules/{ruleset_id}/_rule/{rule_id}).

    • Confirm structure with GET /_query_rules/{ruleset_id}.

    • Validate criteria with POST /_query_rules/{ruleset_id}/_test using the same match_criteria you will pass at search time.

    • Wire the search: POST /{index}/_search must use a rule query whose ruleset_id references the ruleset and whose match_criteria supplies values for every criteria metadata key (e.g., "query_string": "sale"). Place the normal relevance clause inside organic. Creating the ruleset alone does not pin anything — the pin applies only when search includes the rule query.

    Organic tuning path

    • Build a candidate multi_match (or equivalent bool/should) query from the mapping.

    • Optionally inspect analysis with POST /{index}/_analyze on sample query text when tokenization explains misses.

    Decision: Stop after one coherent change set; avoid stacking unrelated edits before testing.

  4. Test and compare top hits. Before and after each candidate, call POST /{index}/_search with the same size (≥ 10), the user's query string, and "track_scores": true. For pinning, the search body must include the rule query from step 3.

    Compare for each run:

    • Top _id values and order

    • _score where relevant

    • Key _source fields (title, description, product id)

    For pinning, confirm the target document (e.g., SKU123) is first when match_criteria matches the query and that organic matches still appear below. For organic tuning, confirm titles and intent-aligned documents rise without relying on sort or keyword exact-match hacks.

    Decision: Ship the candidate that wins on evidence; if none improve results, report what was tried and propose the next lever (e.g., synonyms or additional fields). Data needed: side-by-side top-hit lists from baseline and candidate queries.

Examples

Pin SKU123 for query "sale" on catalog

Wrong: Boost SKU123, sort by _id, or create a ruleset without a rule search query.

Right:

  1. PUT /_query_rules/catalog-sale-pin with a pinned rule, criteria matching query text "sale", actions pinning SKU123.

  2. POST /catalog/_search with:

{
  "query": {
    "rule": {
      "ruleset_id": "catalog-sale-pin",
      "match_criteria": { "query_string": "sale" },
      "organic": {
        "multi_match": {
          "query": "sale",
          "fields": ["title^2", "description"]
        }
      }
    }
  },
  "size": 10
}

Verify SKU123 is hit #1 and remaining hits are organic matches below the pin.

Improve "running shoes" when only description is searched

Mapping provides title and description as text, plus brand and category as keyword.

Wrong: Keep match on description only; sort by price; term query on title.keyword.

Right:

  1. Baseline: POST /catalog/_search with the user's current match on description; record top hits.

  2. Candidate: POST /catalog/_search with:

{
  "query": {
    "multi_match": {
      "query": "running shoes",
      "fields": ["title^2", "description"],
      "type": "best_fields",
      "operator": "or",
      "minimum_should_match": "75%"
    }
  },
  "size": 10
}
  1. Compare top hits — documents with "running shoes" in title should rank above description-only matches. If recall is still thin, consider synonym expansion in a follow-up iteration (not sort-by-price).

Guidelines

  • Ground every field name in the mapping — never invent name, content, or body without checking GET /{index}/_mapping.

  • Query rules for pins, boosts for ranking — merchandising belongs in query rules; field boosts belong in organic queries.

  • Match criteria wiring is mandatory — metadata keys in rule criteria must appear in the search rule.match_criteria object with the runtime values (typically the user's query string).

  • Test before claiming success — run baseline and candidate searches; cite top-hit changes.

  • Keyword fields filter; text fields search — use keyword fields in filter context, not as the primary full-text target for natural language.

  • Always deliver the concrete artifact — even when you cannot connect to a cluster to verify, produce the full ruleset JSON (for pinning) or the candidate query body (for organic tuning), then explain how to verify once the connection is available. Never stop at a high-level outline.

References

Operations

HTTP API (shorthand)elastic CLI command
GET /elastic es info
GET /_cat/indiceselastic es cat indices --index '<pattern>'
GET /{index}/_mappingelastic es indices get-mapping --index '<index>'
PUT /_query_rules/{ruleset_id}elastic es query-rules put-ruleset --ruleset-id '<id>' --rules '<json>'
PUT /_query_rules/{ruleset_id}/_rule/{rule_id}elastic es query-rules put-rule --ruleset-id '<id>' --rule-id '<id>' --type pinned --criteria '<json>' --actions '<json>'
GET /_query_rules/{ruleset_id}elastic es query-rules get-ruleset --ruleset-id '<id>'
POST /_query_rules/{ruleset_id}/_testelastic es query-rules test --ruleset-id '<id>' --match-criteria '<json>'
POST /{index}/_searchelastic es search --index '<index>' --query '<json>'
POST /{index}/_analyzeelastic es indices analyze --index '<index>' --field '<field>' --text '<text>'

Files

references/multi-match-tuning.md

Multi-Match and Field-Boost Tuning

Use this reference when organic relevance is weak and the user wants better ranking, not pinned merchandising.

Read the mapping first

From GET /{index}/_mapping, classify fields:

Mapping typeSearch role
textFull-text retrieval and scoring (title, description, body)
keywordFiltering, sorting, aggregations — not primary natural-language search
text with sub-fieldsOften field for search and field.keyword for exact filters

Short text fields (title, name) signal precision. Long fields (description, body) signal recall. When both exist, search both — do not query only the long field.

Baseline: multi_match across title + description

When a query hits only description, promote title:

{
  "query": {
    "multi_match": {
      "query": "running shoes",
      "fields": ["title^2", "description"],
      "type": "best_fields"
    }
  }
}
  • title^2 — doubles title contribution; tune ^1.5–^3 based on tested top hits.

  • type: "best_fields" — default for short user queries; scores by the best matching field.

  • type: "cross_fields" — treats fields as one combined field; useful when terms should match across fields evenly.

Recall levers (when top hits still miss intent)

Apply one lever at a time; re-test after each change.

Operator and minimum match — for multi-word queries where only one term matches:

{
  "query": {
    "multi_match": {
      "query": "running shoes",
      "fields": ["title^2", "description"],
      "operator": "and",
      "minimum_should_match": "75%"
    }
  }
}

Use operator: "or" with minimum_should_match when strict AND drops too many relevant docs.

Synonyms — when users use alternate product language ("sneakers" vs "running shoes"). Synonym sets apply at index time via analyzers; creating PUT /_synonyms/{set_id} alone does not change an existing index until the index analyzer references that set. Prefer query-time tuning first; propose synonym sets only when recall gaps persist after field boosting.

Analysis inspection — call POST /{index}/_analyze with the same analyzer as the target text field to confirm tokens for sample queries before forcing exact matches.

Testing discipline

  1. Run the current query with POST /{index}/_search; capture top _id, _score, and key _source fields.

  2. Run each candidate query the same way (size ≥ 10).

  3. Compare ordering and explain why the candidate is better — do not declare success without evidence.

Use "explain": true on a single hit when score behavior is unclear.

Anti-patterns for ranking fixes

Wrong approachWhy
sort on price or date instead of _scoreSolves merchandising, not text relevance
term / match on .keyword for analyzed phrasesAnalyzed text requires match / multi_match on text fields
Single-field match on description when title existsIgnores the highest-signal field
Extreme function_score or boosting to pin one SKUUse query rules (pinned) for deterministic promotion
Changing query without re-running searchCannot verify improvement

Field priority (content indices)

When choosing fields and boosts without user guidance:

  1. title, name, subject

  2. summary, headline

  3. description, body, content, text

Boost higher in the list; include lower fields for recall.

Requirements and compatibility

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

The author says: Elasticsearch 8.10 or later (query rules), self-managed, Elastic Cloud Hosted, or Elastic Cloud Serverless. Requires the `elastic` CLI ≥ 0.2 with `stack es` support.

Security

No issues found by our static scan· No issues found

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Created by
elastic
Publisher
Elastic (Official)
Source
elastic/agent-skills · skills/elasticsearch/elasticsearch-search-relevance · commit 09d879d
Licence
Apache License 2.0 (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE)
  • ATTRIBUTION.md (written by AutoGineer)
Synced
Also distributed in
elastic/agent-skills

AutoGineer is not affiliated with or endorsed by elastic.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download elasticsearch-search-relevance.zip