DSL Query API
The DSL Query API lets you search any Semantic Navigation site with the Elasticsearch Query DSL: the same JSON query language whether the site is backed by Solr, Lucene, or Elasticsearch. Viglet Turing translates the DSL to the configured engine and returns an Elasticsearch-shaped response, so you write one query syntax and never re-learn it per backend.
You’d reach for this over the simpler /search REST endpoint when you need the full expressive power of structured queries (bool composition, nested aggregations, range filters, more_like_this) or when you’re porting an existing Elasticsearch client. The same query types are what AI Agents drive through the DSL search tools.
Endpoint
Section titled “Endpoint”POST /api/sn/{siteName}/_search?locale=enGET /api/sn/{siteName}/_search?locale=en| Parameter | Type | Default | Description |
|---|---|---|---|
siteName |
path | required | The Semantic Navigation site name |
locale |
query | en |
Search 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.
Engines that serve this API
Section titled “Engines that serve this API”Solr, Elasticsearch and Lucene translate the whole syntax. Adobe AEM Content AI serves a defined subset and refuses the rest. See Compatibility Matrix → Adobe AEM Content AI.
A site bound to an engine with no DSL implementation at all gets 501 Not Implemented, naming the engine and the ones that do work; so does a clause Content AI
cannot express:
{ "type": "tag:viglet.com,2026:errors/unsupported-engine", "title": "Not Implemented", "status": 501, "detail": "The DSL query API is not implemented for the 'contentai' search engine. Engines that serve it: elasticsearch, lucene, solr.", "engine": "contentai"}404 still means what it always did: no such site, or no such locale on that site.
Quick Start
Section titled “Quick Start”Simple Match Query
Section titled “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
Section titled “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
Section titled “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
Section titled “Supported Queries”Full-text Queries
Section titled “Full-text Queries”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
Section titled “multi_match”Search across multiple fields.
{ "query": { "multi_match": { "query": "artificial intelligence", "fields": ["title", "body", "abstract"] } }}match_phrase
Section titled “match_phrase”Exact phrase search with optional slop (word distance).
{ "query": { "match_phrase": { "title": { "query": "enterprise search", "slop": 2 } } } }match_phrase_prefix
Section titled “match_phrase_prefix”Autocomplete-style phrase matching.
{ "query": { "match_phrase_prefix": { "title": { "query": "enter", "max_expansions": 10 } } } }match_bool_prefix
Section titled “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
Section titled “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
Section titled “query_string”Lucene query string syntax.
{ "query": { "query_string": { "query": "title:search AND status:published", "default_field": "title" } } }simple_query_string
Section titled “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
Section titled “Term-level Queries”Exact match on a field (not analyzed).
{ "query": { "term": { "status": "published" } } }Match any of multiple values.
{ "query": { "terms": { "status": ["published", "review"] } } }terms_set
Section titled “terms_set”Terms with dynamic minimum_should_match.
{ "query": { "terms_set": { "tags": { "terms": ["search", "ai", "nlp"], "minimum_should_match_field": "required_matches" } } }}Range queries with gte, gt, lte, lt.
{ "query": { "range": { "date": { "gte": "2025-01-01", "lte": "2026-12-31" } } } }exists
Section titled “exists”Check if a field has a value.
{ "query": { "exists": { "field": "thumbnail" } } }prefix
Section titled “prefix”Prefix matching.
{ "query": { "prefix": { "title": "ent" } } }wildcard
Section titled “wildcard”Wildcard pattern matching (* and ?).
{ "query": { "wildcard": { "title": "enter*" } } }regexp
Section titled “regexp”Regular expression matching.
{ "query": { "regexp": { "title": { "value": "enter.*ch", "flags": "ALL" } } } }Fuzzy (approximate) matching.
{ "query": { "fuzzy": { "title": { "value": "serch", "fuzziness": 2 } } } }Match specific document IDs.
{ "query": { "ids": { "values": ["doc1", "doc2", "doc3"] } } }Compound Queries
Section titled “Compound Queries”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
Section titled “constant_score”Wraps a filter query and assigns a constant score.
{ "query": { "constant_score": { "filter": { "term": { "status": "published" } }, "boost": 1.5 } } }dis_max
Section titled “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
Section titled “boosting”Boost positive matches while demoting negative matches.
{ "query": { "boosting": { "positive": { "match": { "title": "search" } }, "negative": { "term": { "status": "deprecated" } }, "negative_boost": 0.2 } }}function_score
Section titled “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
Section titled “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
Section titled “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
Section titled “Nested & Join Queries”nested
Section titled “nested”Search within nested objects.
{ "query": { "nested": { "path": "comments", "query": { "match": { "comments.text": "great article" } }, "score_mode": "avg" } }}has_child
Section titled “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
Section titled “has_parent”Find child documents by parent document criteria.
{ "query": { "has_parent": { "parent_type": "question", "query": { "match": { "title": "search" } }, "score": true } }}Geo Queries
Section titled “Geo Queries”geo_distance
Section titled “geo_distance”Filter by distance from a point.
{ "query": { "geo_distance": { "distance": "10km", "location": { "lat": 40.73, "lon": -73.93 } } }}geo_bounding_box
Section titled “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
Section titled “geo_shape”Filter by geographic shape.
{ "query": { "geo_shape": { "location": { "shape": { "type": "envelope", "coordinates": [[-74.1, 40.73], [-71.12, 40.01]] }, "relation": "within" } } }}Vector Search
Section titled “Vector Search”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
Section titled “Span Queries”span_term, span_near, span_or, span_not, span_first
Section titled “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
Section titled “Specialized Queries”more_like_this
Section titled “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
Section titled “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
Section titled “rank_feature, distance_feature, percolate, wrapper”Additional specialized queries for ranking features, distance-based scoring, reverse search, and base64-encoded queries.
Aggregations
Section titled “Aggregations”Bucket Aggregations
Section titled “Bucket Aggregations”Group documents by field values.
{ "aggs": { "categories": { "terms": { "field": "category", "size": 10 } } }}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
Section titled “date_histogram”Group documents by date intervals.
{ "aggs": { "monthly": { "date_histogram": { "field": "date", "calendar_interval": "month", "format": "yyyy-MM" } } }}histogram
Section titled “histogram”Group documents by numeric intervals.
{ "aggs": { "price_histogram": { "histogram": { "field": "price", "interval": 50 } } }}filter / filters
Section titled “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
Section titled “significant_terms, rare_terms, multi_terms, auto_date_histogram”Additional bucket aggregations for statistical analysis.
nested / reverse_nested
Section titled “nested / reverse_nested”Aggregations scoped to nested objects.
composite
Section titled “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
Section titled “sampler / diversified_sampler, adjacency_matrix, variable_width_histogram”Advanced bucket aggregations for sampling, matrix analysis, and adaptive histograms.
Metric Aggregations
Section titled “Metric Aggregations”avg, sum, min, max
Section titled “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
Section titled “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
Section titled “cardinality”Count distinct values.
{ "aggs": { "unique_users": { "cardinality": { "field": "user_id", "precision_threshold": 1000 } } }}percentiles
Section titled “percentiles”Percentile distribution.
{ "aggs": { "latency_percentiles": { "percentiles": { "field": "latency", "percents": [50, 95, 99] } } }}percentile_ranks
Section titled “percentile_ranks”Rank of specific values.
{ "aggs": { "latency_ranks": { "percentile_ranks": { "field": "latency", "values": [100, 200, 500] } } }}value_count, top_hits, top_metrics
Section titled “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
Section titled “median_absolute_deviation, boxplot, string_stats, matrix_stats, t_test, rate, scripted_metric”Advanced statistical aggregations.
Sub-aggregations
Section titled “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
Section titled “Request Features”Pagination
Section titled “Pagination”{ "from": 0, "size": 10 }Cursor-based pagination (search_after)
Section titled “Cursor-based pagination (search_after)”{ "search_after": ["2026-01-01", "doc123"], "size": 10, "sort": [{ "date": "desc" }, "_id"] }Scroll API
Section titled “Scroll API”{ "scroll": "5m", "size": 1000 }Sorting
Section titled “Sorting”{ "sort": [{ "date": "desc" }, { "title": "asc" }, "_score"] }Source Filtering
Section titled “Source Filtering”{ "_source": ["title", "url", "date"] }{ "_source": false }{ "_source": { "includes": ["title", "url"] } }Highlighting
Section titled “Highlighting”{ "highlight": { "fields": { "title": {}, "body": {} }, "pre_tags": ["<mark>"], "post_tags": ["</mark>"], "fragment_size": 150, "number_of_fragments": 3 }}Post Filter
Section titled “Post Filter”Filter hits without affecting aggregations.
{ "query": { "match": { "title": "shoes" } }, "post_filter": { "term": { "color": "red" } }, "aggs": { "all_colors": { "terms": { "field": "color" } } }}Rescore
Section titled “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)
Section titled “Collapse (Field Collapsing)”Deduplicate results by a field.
{ "query": { "match": { "title": "search" } }, "collapse": { "field": "user_id", "inner_hits": { "name": "recent", "size": 3 } }}Suggest
Section titled “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
Section titled “Additional Features”| Feature | Example |
|---|---|
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
Section titled “Architecture”The DSL Query API uses a Strategy Pattern with three executor implementations:
graph TB A[POST /api/sn/site/_search] --> B[TurDslSearchService] B --> C{Resolve Engine} C -->|Solr| D[TurDslSolrExecutor] C -->|Lucene| E[TurDslLuceneExecutor] C -->|Elasticsearch| F[TurDslElasticsearchExecutor] D --> G[Apache Solr] E --> H[Apache Lucene] F --> I[Elasticsearch]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
Section titled “How it Works”- Request arrives at the
_searchendpoint - TurDslSearchService resolves the site and its engine type via
TurSearchEnginePluginFactory - 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
Queryobjects (BooleanQuery, TermQuery, etc.)
- Response is built in Elasticsearch-compatible format regardless of engine
Related Pages
Section titled “Related Pages”- DSL Compatibility Matrix: which DSL features each engine supports
- Search Engine Configuration: Solr / Elasticsearch / Lucene backends
- Semantic Navigation: the sites these queries run against
- Tool Calling: the DSL tools AI Agents use
- REST API Reference: the simpler
/searchendpoint