Skip to main content

DSL Query API

Turing ES provides an Elasticsearch-compatible Query DSL endpoint that translates queries to the configured search engine backend (Solr, Lucene, or Elasticsearch). This allows you to use the same query syntax regardless of the underlying engine.

Endpoint

POST /api/sn/{siteName}/_search?locale=en
GET /api/sn/{siteName}/_search?locale=en
ParameterTypeDefaultDescription
siteNamepathrequiredThe Semantic Navigation site name
localequeryenSearch locale (e.g., en, pt, en_US)

The GET method performs a match_all search. The POST method accepts a JSON request body following the Elasticsearch _search format.


Quick Start

Simple Match Query

curl -X POST "http://localhost:2700/api/sn/mySite/_search?locale=en" \
-H "Content-Type: application/json" \
-d '{
"query": {
"match": { "title": "enterprise search" }
}
}'

Bool Query with Filters and Pagination

curl -X POST "http://localhost:2700/api/sn/mySite/_search?locale=en" \
-H "Content-Type: application/json" \
-d '{
"query": {
"bool": {
"must": [{ "match": { "title": "machine learning" } }],
"filter": [
{ "term": { "status": "published" } },
{ "range": { "date": { "gte": "2025-01-01" } } }
],
"must_not": [{ "term": { "category": "draft" } }]
}
},
"from": 0,
"size": 10,
"sort": [{ "date": "desc" }, "_score"],
"_source": ["title", "url", "date"],
"highlight": {
"fields": { "title": {}, "body": {} },
"pre_tags": ["<em>"],
"post_tags": ["</em>"]
},
"aggs": {
"by_category": { "terms": { "field": "category", "size": 10 } }
}
}'

Response Format

{
"took": 15,
"timed_out": false,
"hits": {
"total": { "value": 42, "relation": "eq" },
"max_score": 1.5,
"hits": [
{
"_id": "doc1",
"_score": 1.5,
"_source": { "title": "ML Guide", "url": "/ml-guide", "date": "2025-06-01" },
"highlight": { "title": ["<em>Machine Learning</em> Guide"] }
}
]
},
"aggregations": {
"by_category": {
"buckets": [
{ "key": "tutorial", "doc_count": 18 },
{ "key": "research", "doc_count": 12 }
]
}
}
}

Supported Queries

Full-text Queries

match

Full-text search on a single field with optional operator.

{ "query": { "match": { "title": "enterprise search" } } }

With operator:

{ "query": { "match": { "title": { "query": "enterprise search", "operator": "and" } } } }

multi_match

Search across multiple fields.

{
"query": {
"multi_match": {
"query": "artificial intelligence",
"fields": ["title", "body", "abstract"]
}
}
}

match_phrase

Exact phrase search with optional slop (word distance).

{ "query": { "match_phrase": { "title": { "query": "enterprise search", "slop": 2 } } } }

match_phrase_prefix

Autocomplete-style phrase matching.

{ "query": { "match_phrase_prefix": { "title": { "query": "enter", "max_expansions": 10 } } } }

match_bool_prefix

Combines bool query for leading terms with prefix on the last term.

{ "query": { "match_bool_prefix": { "title": "quick brown f" } } }

combined_fields

Search across multiple fields as if they were one combined field.

{
"query": {
"combined_fields": {
"query": "enterprise search",
"fields": ["title", "body"],
"operator": "and"
}
}
}

query_string

Lucene query string syntax.

{ "query": { "query_string": { "query": "title:search AND status:published", "default_field": "title" } } }

simple_query_string

Simple query string syntax (no exceptions on parse errors).

{
"query": {
"simple_query_string": {
"query": "\"enterprise search\" +platform",
"fields": ["title", "body"],
"default_operator": "AND"
}
}
}

Term-level Queries

term

Exact match on a field (not analyzed).

{ "query": { "term": { "status": "published" } } }

terms

Match any of multiple values.

{ "query": { "terms": { "status": ["published", "review"] } } }

terms_set

Terms with dynamic minimum_should_match.

{
"query": {
"terms_set": {
"tags": {
"terms": ["search", "ai", "nlp"],
"minimum_should_match_field": "required_matches"
}
}
}
}

range

Range queries with gte, gt, lte, lt.

{ "query": { "range": { "date": { "gte": "2025-01-01", "lte": "2026-12-31" } } } }

exists

Check if a field has a value.

{ "query": { "exists": { "field": "thumbnail" } } }

prefix

Prefix matching.

{ "query": { "prefix": { "title": "ent" } } }

wildcard

Wildcard pattern matching (* and ?).

{ "query": { "wildcard": { "title": "enter*" } } }

regexp

Regular expression matching.

{ "query": { "regexp": { "title": { "value": "enter.*ch", "flags": "ALL" } } } }

fuzzy

Fuzzy (approximate) matching.

{ "query": { "fuzzy": { "title": { "value": "serch", "fuzziness": 2 } } } }

ids

Match specific document IDs.

{ "query": { "ids": { "values": ["doc1", "doc2", "doc3"] } } }

Compound Queries

bool

Combine multiple clauses with must, should, must_not, and filter.

{
"query": {
"bool": {
"must": [{ "match": { "title": "search" } }],
"should": [{ "match": { "category": "premium" } }],
"must_not": [{ "term": { "status": "archived" } }],
"filter": [{ "range": { "date": { "gte": "2025-01-01" } } }],
"minimum_should_match": 1
}
}
}

constant_score

Wraps a filter query and assigns a constant score.

{ "query": { "constant_score": { "filter": { "term": { "status": "published" } }, "boost": 1.5 } } }

dis_max

Returns documents matching any query, using the best-matching score.

{
"query": {
"dis_max": {
"queries": [
{ "match": { "title": "search" } },
{ "match": { "body": "search" } }
],
"tie_breaker": 0.3
}
}
}

boosting

Boost positive matches while demoting negative matches.

{
"query": {
"boosting": {
"positive": { "match": { "title": "search" } },
"negative": { "term": { "status": "deprecated" } },
"negative_boost": 0.2
}
}
}

function_score

Custom scoring with multiple functions.

{
"query": {
"function_score": {
"query": { "match_all": {} },
"functions": [
{ "filter": { "term": { "category": "premium" } }, "weight": 2.0 },
{
"field_value_factor": {
"field": "popularity",
"factor": 1.2,
"modifier": "log1p",
"missing": 1
}
}
],
"score_mode": "sum",
"boost_mode": "multiply",
"max_boost": 10
}
}
}

script_score

Score using a script.

{
"query": {
"script_score": {
"query": { "match": { "title": "search" } },
"script": {
"source": "_score * doc['popularity'].value",
"lang": "painless",
"params": { "factor": 2 }
}
}
}
}

pinned

Pin specific documents to the top of results.

{
"query": {
"pinned": {
"ids": ["featured-doc-1", "featured-doc-2"],
"organic": { "match": { "title": "search" } }
}
}
}

Nested & Join Queries

nested

Search within nested objects.

{
"query": {
"nested": {
"path": "comments",
"query": { "match": { "comments.text": "great article" } },
"score_mode": "avg"
}
}
}

has_child

Find parent documents by child document criteria.

{
"query": {
"has_child": {
"type": "answer",
"query": { "match": { "body": "elasticsearch" } },
"min_children": 1,
"max_children": 10
}
}
}

has_parent

Find child documents by parent document criteria.

{
"query": {
"has_parent": {
"parent_type": "question",
"query": { "match": { "title": "search" } },
"score": true
}
}
}

Geo Queries

geo_distance

Filter by distance from a point.

{
"query": {
"geo_distance": {
"distance": "10km",
"location": { "lat": 40.73, "lon": -73.93 }
}
}
}

geo_bounding_box

Filter by bounding box.

{
"query": {
"geo_bounding_box": {
"location": {
"top_left": { "lat": 40.73, "lon": -74.1 },
"bottom_right": { "lat": 40.01, "lon": -71.12 }
}
}
}
}

geo_shape

Filter by geographic shape.

{
"query": {
"geo_shape": {
"location": {
"shape": { "type": "envelope", "coordinates": [[-74.1, 40.73], [-71.12, 40.01]] },
"relation": "within"
}
}
}
}

knn

K-nearest neighbors vector search (semantic search).

{
"query": {
"knn": {
"field": "embedding",
"query_vector": [0.1, 0.2, 0.3, 0.4],
"k": 10,
"num_candidates": 100,
"similarity": 0.8,
"filter": { "term": { "status": "published" } }
}
}
}

Span Queries

span_term, span_near, span_or, span_not, span_first

Low-level positional queries for advanced use cases.

{
"query": {
"span_near": {
"clauses": [
{ "span_term": { "title": "enterprise" } },
{ "span_term": { "title": "search" } }
],
"slop": 2,
"in_order": true
}
}
}

Specialized Queries

more_like_this

Find similar documents.

{
"query": {
"more_like_this": {
"fields": ["title", "body"],
"like": "enterprise search platform with AI capabilities",
"min_term_freq": 1,
"min_doc_freq": 1
}
}
}

intervals

Fine-grained control over term proximity.

{
"query": {
"intervals": {
"body": {
"match": {
"query": "enterprise search",
"max_gaps": 2,
"ordered": true
}
}
}
}
}

rank_feature, distance_feature, percolate, wrapper

Additional specialized queries for ranking features, distance-based scoring, reverse search, and base64-encoded queries.


Aggregations

Bucket Aggregations

terms

Group documents by field values.

{
"aggs": {
"categories": { "terms": { "field": "category", "size": 10 } }
}
}

range

Group documents by numeric or date ranges.

{
"aggs": {
"price_ranges": {
"range": {
"field": "price",
"ranges": [
{ "key": "cheap", "to": 50 },
{ "key": "mid", "from": 50, "to": 200 },
{ "key": "expensive", "from": 200 }
]
}
}
}
}

date_histogram

Group documents by date intervals.

{
"aggs": {
"monthly": {
"date_histogram": {
"field": "date",
"calendar_interval": "month",
"format": "yyyy-MM"
}
}
}
}

histogram

Group documents by numeric intervals.

{
"aggs": {
"price_histogram": { "histogram": { "field": "price", "interval": 50 } }
}
}

filter / filters

Single or multiple named filters.

{
"aggs": {
"status_counts": {
"filters": {
"filters": {
"active": { "term": { "status": "active" } },
"archived": { "term": { "status": "archived" } }
}
}
}
}
}

significant_terms, rare_terms, multi_terms, auto_date_histogram

Additional bucket aggregations for statistical analysis.

nested / reverse_nested

Aggregations scoped to nested objects.

composite

Paginated aggregations for large cardinality fields.

{
"aggs": {
"paginated": {
"composite": {
"size": 100,
"sources": [
{ "category": { "terms": { "field": "category" } } }
]
}
}
}
}

sampler / diversified_sampler, adjacency_matrix, variable_width_histogram

Advanced bucket aggregations for sampling, matrix analysis, and adaptive histograms.

Metric Aggregations

avg, sum, min, max

Basic numeric operations.

{
"aggs": {
"avg_price": { "avg": { "field": "price" } },
"total_sales": { "sum": { "field": "amount" } },
"cheapest": { "min": { "field": "price" } },
"most_expensive": { "max": { "field": "price" } }
}
}

stats / extended_stats

Multiple statistics in one aggregation.

{
"aggs": {
"price_stats": { "stats": { "field": "price" } }
}
}

Response:

{
"price_stats": {
"values": { "count": 100, "min": 5.0, "max": 999.0, "avg": 125.5, "sum": 12550.0 }
}
}

cardinality

Count distinct values.

{
"aggs": {
"unique_users": { "cardinality": { "field": "user_id", "precision_threshold": 1000 } }
}
}

percentiles

Percentile distribution.

{
"aggs": {
"latency_percentiles": {
"percentiles": { "field": "latency", "percents": [50, 95, 99] }
}
}
}

percentile_ranks

Rank of specific values.

{
"aggs": {
"latency_ranks": {
"percentile_ranks": { "field": "latency", "values": [100, 200, 500] }
}
}
}

value_count, top_hits, top_metrics

Count, top documents, and top metrics per bucket.

median_absolute_deviation, boxplot, string_stats, matrix_stats, t_test, rate, scripted_metric

Advanced statistical aggregations.

Sub-aggregations

Nest aggregations within bucket aggregations for multi-dimensional analysis.

{
"aggs": {
"by_category": {
"terms": { "field": "category", "size": 10 },
"aggs": {
"avg_price": { "avg": { "field": "price" } },
"top_docs": { "top_hits": { "size": 3 } }
}
}
}
}

Request Features

Pagination

{ "from": 0, "size": 10 }

Cursor-based pagination (search_after)

{ "search_after": ["2026-01-01", "doc123"], "size": 10, "sort": [{ "date": "desc" }, "_id"] }

Scroll API

{ "scroll": "5m", "size": 1000 }

Sorting

{ "sort": [{ "date": "desc" }, { "title": "asc" }, "_score"] }

Source Filtering

{ "_source": ["title", "url", "date"] }
{ "_source": false }
{ "_source": { "includes": ["title", "url"] } }

Highlighting

{
"highlight": {
"fields": { "title": {}, "body": {} },
"pre_tags": ["<mark>"],
"post_tags": ["</mark>"],
"fragment_size": 150,
"number_of_fragments": 3
}
}

Post Filter

Filter hits without affecting aggregations.

{
"query": { "match": { "title": "shoes" } },
"post_filter": { "term": { "color": "red" } },
"aggs": {
"all_colors": { "terms": { "field": "color" } }
}
}

Rescore

Re-score top N results with a secondary query.

{
"query": { "match": { "title": "search" } },
"rescore": [{
"window_size": 50,
"query": {
"rescore_query": { "match_phrase": { "title": "enterprise search" } },
"query_weight": 0.7,
"rescore_query_weight": 1.2
}
}]
}

Collapse (Field Collapsing)

Deduplicate results by a field.

{
"query": { "match": { "title": "search" } },
"collapse": {
"field": "user_id",
"inner_hits": { "name": "recent", "size": 3 }
}
}

Suggest

Term, phrase, and completion suggestions.

{
"suggest": {
"title-suggest": {
"text": "enterprse",
"term": { "field": "title" }
},
"autocomplete": {
"text": "ent",
"completion": { "field": "suggest_field", "size": 5, "skip_duplicates": true }
}
}
}

Additional Features

FeatureExample
min_score"min_score": 0.5
timeout"timeout": "5s"
explain"explain": true
profile"profile": true
version"version": true
script_fields"script_fields": {"x": {"script": {"source": "doc['price'].value * 2"}}}
stored_fields"stored_fields": ["title", "date"]
docvalue_fields"docvalue_fields": ["date", "price"]
indices_boost"indices_boost": [{"index1": 1.5}]
track_total_hits"track_total_hits": true or "track_total_hits": 10000
preference"preference": "_local"
routing"routing": "user123"
terminate_after"terminate_after": 1000
seq_no_primary_term"seq_no_primary_term": true
pit"pit": {"id": "abc", "keep_alive": "5m"}

Architecture

The DSL Query API uses a Strategy Pattern with three executor implementations:

The engine is resolved automatically from the SN site's Search Engine instance configuration. The same JSON request body works across all three engines.

How it Works

  1. Request arrives at the _search endpoint
  2. TurDslSearchService resolves the site and its engine type via TurSearchEnginePluginFactory
  3. The appropriate executor translates the DSL query to the native engine format:
    • Elasticsearch: Direct 1:1 mapping using the Java API client
    • Solr: Translates to Solr query syntax, facets, and parameters
    • Lucene: Translates to Lucene Query objects (BooleanQuery, TermQuery, etc.)
  4. Response is built in Elasticsearch-compatible format regardless of engine

See Also