Query string query

A query_string query parses the query string based on the query string syntax. It provides for creating powerful yet concise queries that can incorporate wildcards and search multiple fields.

Searches with query_string queries do not return nested documents. To search nested fields, use the nested query.

Query string query has a strict syntax and returns an error in case of invalid syntax. Therefore, it does not work well for search box applications. For a less strict alternative, consider using simple_query_string query. If you don’t need query syntax support, use the match query.

Query string syntax

Query string syntax is based on Apache Lucene query syntax.

You can use query string syntax in the following cases:

  1. In a query_string query, for example:

    1. GET _search
    2. {
    3. "query": {
    4. "query_string": {
    5. "query": "the wind AND (rises OR rising)"
    6. }
    7. }
    8. }

    copy

  2. In the OpenSearch Dashboards Discover or Dashboard apps, if you turn off DQL, as shown in the following image. Using query string syntax in OpenSearch Dashboards Discover

DQL and Query string query (Lucene) language are the two search bar language options in Discover and Dashboards. To compare these language options, see Discover and Dashboard search bar.

  1. If you search using the HTTP request query parameters, for example:

    1. GET _search?q=wind

A query string consists of terms and operators. A term is a single word (for example, in the query wind rises, the terms are wind and rises). If several terms are surrounded by quotation marks, they are treated as one phrase where words are marched in the order they appear (for example, "wind rises"). Operators (such as OR, AND, and NOT) specify the Boolean logic used to interpret text in the query string.

The examples in this section use an index containing the following mapping and documents:

  1. PUT /testindex
  2. {
  3. "mappings": {
  4. "properties": {
  5. "title": {
  6. "type": "text",
  7. "fields": {
  8. "english": {
  9. "type": "text",
  10. "analyzer": "english"
  11. }
  12. }
  13. }
  14. }
  15. }
  16. }

copy

  1. PUT /testindex/_doc/1
  2. {
  3. "title": "The wind rises"
  4. }

copy

  1. PUT /testindex/_doc/2
  2. {
  3. "title": "Gone with the wind",
  4. "description": "A 1939 American epic historical film"
  5. }

copy

  1. PUT /testindex/_doc/3
  2. {
  3. "title": "Windy city"
  4. }

copy

  1. PUT /testindex/_doc/4
  2. {
  3. "article title": "Wind turbines"
  4. }

copy

Reserved characters

The following is a list of reserved characters for the query string query:

+, -, =, &&, ||, >, <, !, (, ),{, }, [, ], ^, ", ~, *, ?, :, \, /

Escape reserved characters with a backslash (\). When sending a JSON request, use a double backslash (\\) to escape reserved characters (because the backslash character is itself reserved, you must escape the backslash with another backslash).

For example, to search for an expression 2*3, specify the query string: 2\\*3:

  1. GET /testindex/_search
  2. {
  3. "query": {
  4. "query_string": {
  5. "query": "title: 2\\*3"
  6. }
  7. }
  8. }

copy

The > and < signs cannot be escaped. They are interpreted as a range query.

White space characters and empty queries

White space characters are not considered operators. If a query string is empty or only contains white space characters, the query does not return results.

Field names

Specify the field name before the colon. The following table contains example queries with field names.

Query in the querystring queryQuery in DiscoverCriterion for a document to matchMatching documents from the testindex index
title: windtitle: windThe title field contains the word wind.1, 2
title: (wind OR windy)title: (wind OR windy)The title field contains the word wind or the word windy.1, 2, 3
title: \”wind rises\”title: “wind rises”The title field contains the phrase wind rises. Escape quotation marks with a backslash.1
article\ title: windarticle\ title: windThe article title field contains the word wind. Escape the space character with a backslash.4
title.\: risetitle.\: riseEvery field that begins with title. (in this example, title.english) contains the word rise. Escape the wildcard character with a backslash.1
_exists: descriptionexists: descriptionThe field description exists.2

Wildcard expressions

You can specify wildcard expressions using special characters: ? replaces a single character and * replaces zero or more characters.

Example

The following query searches for the title containing the word gone and a description that contains a word starting with hist:

  1. GET /testindex/_search
  2. {
  3. "query": {
  4. "query_string": {
  5. "query": "title: gone AND description: hist*"
  6. }
  7. }
  8. }

copy

Wildcard queries can use a significant amount of memory, which can degrade performance. Wildcards at the beginning of a word (for example, *cal) are the most expensive because matching documents on such wildcards requires examining all terms in the index. To disable leading wildcards, set allow_leading_wildcard to false.

For efficiency, pure wildcards such as * are rewritten as exists queries. Therefore, the description: * wildcard will match documents containing an empty value in the description field but will not match documents in which the description field is either missing or has a null value.

If you set analyze_wildcard to true, OpenSearch will analyze queries that end with a * (such as hist*). Consequently, OpenSearch will build a Boolean query comprising the resulting tokens by taking exact matches on the first n-1 tokens and a prefix match on the last token.

Regular expressions

To specify regular expression patterns in a query string, surround them with forward slashes (/), for example title: /w[a-z]nd/.

The allow_leading_wildcard parameter does not apply to regular expressions. For example, a query string such as /.*d/ will examine all terms in the index.

Fuzziness

You can run fuzzy queries using the ~ operator, for example title: rise~.

The query searches for documents containing terms that are similar to the search term within the maximum allowed edit distance. The edit distance is defined as the Damerau-Levenshtein distance, which measures the number of one-character changes (insertions, deletions, substitutions, or transpositions) needed to change one term to another term.

The default edit distance of 2 should catch 80% of misspellings. To change the default edit distance, specify the new edit distance after the ~ operator. For example, to set the edit distance to 1, use the query title: rise~1.

Do not mix fuzzy and wildcard operators. If you specify both fuzzy and wildcard operators, one of the operators will not be applied. For example, if you can search for wnid*~1, the wildcard operator * will be applied but the fuzzy operator ~1 will not be applied.

Proximity queries

A proximity query does not require the search phrase to be in the specified order. It allows the words in the phrase to be in a different order or separated by other words. A proximity query specifies a maximum edit distance of words in a phrase. For example, the following query allows an edit distance of 4 when matching the words in the specified phrase:

  1. GET /testindex/_search
  2. {
  3. "query": {
  4. "query_string": {
  5. "query": "title: \"wind gone\"~4"
  6. }
  7. }
  8. }

copy

When OpenSearch matches documents, the closer the words in the document to the word order specified in the query (the less the edit distance), the higher the document’s relevance score.

Ranges

To specify a range for a numeric, string, or date field, use square brackets ([min TO max]) for an inclusive range and curly braces ({min TO max}) for an exclusive range. You can also mix square brackets and curly braces to include or exclude the lower and upper bound (for example, {min TO max]).

The dates for a date range must be provided in the format that you used when mapping the field containing the date. For more information about supported date formats, see Formats.

The following table provides range syntax examples.

Data typeQueryQuery string
NumericDocuments whose account numbers are from 1 to 15, inclusive.account_number: [1 TO 15] or
account_number: (>=1 AND <=15) or
account_number: (+>=1 +<=15)
 Documents whose account numbers are 15 and greater.account_number: [15 TO ] or
account_number: >=15 (note no space after the >= sign)
StringDocuments where last name is from Bates, inclusive, to Duke, exclusive.lastname: [Bates TO Duke} or
lastname: (>=Bates AND <Duke)
 Documents where last name precedes Bates alphabetically.lastname: { TO Bates} or
lastname: <Bates (note no space after the < sign)
DateDocuments where the release date is between 03/21/2023 and 09/25/2023, inclusive.release_date: [03/21/2023 TO 09/25/2023]

As an alternative to specifying a range in a query string, you can use a range query, which provides a more reliable syntax.

Boosting

Use the caret (^) boost operator to boost the relevance score of documents by a multiplier. Values in the [0, 1) range decrease relevance, and values greater than 1 increase relevance. Default is 1.

The following table provides boost examples.

TypeDescriptionQuery string
Word boostFind all addresses containing the word street and boost the ones containing the word Madison.address: Madison^2 street
Phrase boostFind documents with the title containing the phrase wind rises, boosted by 2.title: \”wind rises\”^2
 Find documents with the title containing the words wind rises, and boost the documents containing the phrase wind rises by 2.title: (wind rises)^2

Boolean operators

When you provide search terms in the query, by default, the query returns documents containing at least one of the provided terms. You can use the default_operator parameter to specify an operator for all terms. Thus, if you set the default_operator to AND, all terms will be required, whereas if you set it to OR, all terms will be optional.

+ and - operators

If you want more granular control over the required and optional terms, you can use the + and - operators. The + operator makes the term following it required, while the - operator excludes the term following it.

For example, in the query string title: (gone +wind -turbines) specifies that the term gone is optional, the term wind must be present and the term turbines must not be present in the title of the matching documents:

  1. GET /testindex/_search
  2. {
  3. "query": {
  4. "query_string": {
  5. "query": "title: (gone +wind -turbines)"
  6. }
  7. }
  8. }

copy

The query returns two matching documents:

  1. {
  2. "_index": "testindex",
  3. "_id": "2",
  4. "_score": 1.3159468,
  5. "_source": {
  6. "title": "Gone with the wind",
  7. "description": "A 1939 American epic historical film"
  8. }
  9. },
  10. {
  11. "_index": "testindex",
  12. "_id": "1",
  13. "_score": 0.3438858,
  14. "_source": {
  15. "title": "The wind rises"
  16. }
  17. }

The preceding query is equivalent to the following Boolean query:

  1. GET testindex/_search
  2. {
  3. "query": {
  4. "bool": {
  5. "must": {
  6. "match": {
  7. "title": "wind"
  8. }
  9. },
  10. "should": {
  11. "match": {
  12. "title": "gone"
  13. }
  14. },
  15. "must_not": {
  16. "match": {
  17. "title": "turbines"
  18. }
  19. }
  20. }
  21. }
  22. }

Conventional Boolean operators

Alternatively, you can use the following Boolean operators: AND, &&, OR, ||, NOT, !. However, these operators do not follow the precedence rules, so you must use parentheses to specify precedence when using multiple Boolean operators. For example, the query string title: (gone +wind -turbines) can be rewritten as follows using Boolean operators:

title: ((gone AND wind) OR wind) AND NOT turbines

Run the following query that contains the rewritten query string:

  1. GET testindex/_search
  2. {
  3. "query": {
  4. "query_string": {
  5. "query": "title: ((gone AND wind) OR wind) AND NOT turbines"
  6. }
  7. }
  8. }

copy

The query returns the same results as the query that uses the + and - operators. However, note that the relevance scores of the matching documents are not the same as in the previous results:

  1. {
  2. "_index": "testindex",
  3. "_id": "2",
  4. "_score": 1.6166971,
  5. "_source": {
  6. "title": "Gone with the wind",
  7. "description": "A 1939 American epic historical film"
  8. }
  9. },
  10. {
  11. "_index": "testindex",
  12. "_id": "1",
  13. "_score": 0.3438858,
  14. "_source": {
  15. "title": "The wind rises"
  16. }
  17. }

copy

Grouping

Group multiple clauses or terms into subqueries using parentheses. For example, the following query searches for documents containing the words gone or rises that must contain the word wind in the title:

  1. GET testindex/_search
  2. {
  3. "query": {
  4. "query_string": {
  5. "query": "title: (gone OR rises) AND wind"
  6. }
  7. }
  8. }

The results contain the two matching documents:

  1. {
  2. "_index": "testindex",
  3. "_id": "1",
  4. "_score": 1.5046883,
  5. "_source": {
  6. "title": "The wind rises"
  7. }
  8. },
  9. {
  10. "_index": "testindex",
  11. "_id": "2",
  12. "_score": 1.3159468,
  13. "_source": {
  14. "title": "Gone with the wind",
  15. "description": "A 1939 American epic historical film"
  16. }
  17. }

You can also use grouping to boost subquery results or to target the specified field, for example title:(gone AND wind) description:(historical film)^2.

Searching multiple fields

To search multiple fields, use the fields parameter. When you provide the fields parameter, the query is rewritten as field_1: query OR field_2: query ....

For example, the following query searches for the terms wind or film in the title and description fields:

  1. GET testindex/_search
  2. {
  3. "query": {
  4. "query_string": {
  5. "fields": [ "title", "description" ],
  6. "query": "wind AND film"
  7. }
  8. }
  9. }

copy

The preceding query is equivalent to the following query that does not provide the fields parameter:

  1. GET testindex/_search
  2. {
  3. "query": {
  4. "query_string": {
  5. "query": "(title:wind OR description:wind) AND (title:film OR description:film)"
  6. }
  7. }
  8. }

Searching multiple subfields of a field

To search all inner fields of a field, you can use a wildcard. For example, to search all subfields within the address field, use the following query:

  1. GET /testindex/_search
  2. {
  3. "query": {
  4. "query_string" : {
  5. "fields" : ["address.*"],
  6. "query" : "New AND (York OR Jersey)"
  7. }
  8. }
  9. }

copy

The preceding query is equivalent to the following query that does not provide the fields parameter (note that the * is escaped with \\):

  1. GET /testindex/_search
  2. {
  3. "query": {
  4. "query_string" : {
  5. "query" : "address.\\*: New AND (York OR Jersey)"
  6. }
  7. }
  8. }

Boosting

The subqueries that are generated from each search term are combined using a dis_max query with a tie_breaker. To boost individual fields, use the ^ operator. For example, the following query boosts the title field by a factor of 2:

  1. GET testindex/_search
  2. {
  3. "query": {
  4. "query_string": {
  5. "fields": [ "title^2", "description" ],
  6. "query": "wind AND film"
  7. }
  8. }
  9. }

copy

To boost all subfields of a field, specify the boost operator after the wildcard:

  1. GET /testindex/_search
  2. {
  3. "query": {
  4. "query_string" : {
  5. "fields" : ["work_address", "address.*^2"],
  6. "query" : "New AND (York OR Jersey)"
  7. }
  8. }
  9. }

Parameters for multiple field searches

When searching multiple fields, you can pass the additional optional type parameter to the query_string query.

ParameterData typeDescription
typeStringDetermines how OpenSearch executes the query and scores the results. Valid values are best_fields, bool_prefix, most_fields, cross_fields, phrase, and phrase_prefix. Default is best_fields. For descriptions of valid values, see Multi-match query types.

Synonyms in the query_string query

The query_string query supports multi-term synonym expansion with the synonym_graph token filter. If you use the synonym_graph token filter, OpenSearch creates a match phrase query for each synonym.

The auto_generate_synonyms_phrase_query parameter specifies whether to create a match phrase query automatically for multi-term synonyms. By default, auto_generate_synonyms_phrase_query is true, so if you specify ml, machine learning as synonyms and search for ml, OpenSearch searches for ml OR "machine learning".

Alternatively, you can match multi-term synonyms using conjunctions. If you set auto_generate_synonyms_phrase_query to false, OpenSearch searches for ml OR (machine AND learning).

For example, the following query searches for the text ml models and specifies not to auto-generate a match phrase query for each synonym:

  1. GET /testindex/_search
  2. {
  3. "query": {
  4. "query_string": {
  5. "default_field": "title",
  6. "query": "ml models",
  7. "auto_generate_synonyms_phrase_query": false
  8. }
  9. }
  10. }

copy

For this query, OpenSearch creates the following Boolean query: (ml OR (machine AND learning)) models.

Minimum should match

The query_string query splits the query around each operator and creates a Boolean query for the entire input. The minimum_should_match parameter specifies the minimum number of terms a document must match to be returned in search results. For example, the following query specifies that the description field must match at least two terms for each search result:

  1. GET /testindex/_search
  2. {
  3. "query": {
  4. "query_string": {
  5. "fields": [
  6. "description"
  7. ],
  8. "query": "historical epic film",
  9. "minimum_should_match": 2
  10. }
  11. }
  12. }

copy

For this query, OpenSearch creates the following Boolean query: (description:historical description:epic description:film)~2.

Minimum should match with multiple fields

If you specify multiple fields in a query_string query, OpenSearch creates a dis_max query for the specified fields. If you don’t explicitly specify an operator for the query terms, the whole query text is treated as one clause. OpenSearch builds a query for each field using this single clause. The final Boolean query contains a single clause that corresponds to the dis_max query for all fields, therefore the minimum_should_match parameter is not applied.

For example, in the following query, historical epic heroic is treated as a single clause:

  1. GET /testindex/_search
  2. {
  3. "query": {
  4. "query_string": {
  5. "fields": [
  6. "title",
  7. "description"
  8. ],
  9. "query": "historical epic heroic",
  10. "minimum_should_match": 2
  11. }
  12. }
  13. }

copy

For this query, OpenSearch creates the following Boolean query: ((title:historical title:epic title:heroic) | (description:historical description:epic description:heroic)).

If you add explicit operators (AND or OR) to the query terms, each term is considered a separate clause, to which the minimum_should_match parameter can be applied. For example, in the following query, historical, epic, and heroic are considered separate clauses:

  1. GET /testindex/_search
  2. {
  3. "query": {
  4. "query_string": {
  5. "fields": [
  6. "title",
  7. "description"
  8. ],
  9. "query": "historical OR epic OR heroic",
  10. "minimum_should_match": 2
  11. }
  12. }
  13. }

copy

For this query, OpenSearch creates the following Boolean query: ((title:historical | description:historical) (description:epic | title:epic) (description:heroic | title:heroic))~2. The query matches at least two of the three clauses. Each clause represents a dis_max query on both the title and description fields for each term.

Alternatively, to ensure that minimum_should_match can be applied, you can set the type parameter to cross_fields. This indicates that the fields with the same analyzer should be grouped together when the input text is analyzed:

  1. GET /testindex/_search
  2. {
  3. "query": {
  4. "query_string": {
  5. "fields": [
  6. "title",
  7. "description"
  8. ],
  9. "query": "historical epic heroic",
  10. "type": "cross_fields",
  11. "minimum_should_match": 2
  12. }
  13. }
  14. }

copy

For this query, OpenSearch creates the following Boolean query: ((title:historical | description:historical) (description:epic | title:epic) (description:heroic | title:heroic))~2.

However, if you use different analyzers, you must use explicit operators in the query to ensure that the minimum_should_match parameter is applied to each term.

Parameters

The following table lists the parameters that query_string query supports. All parameters except query are optional.

ParameterData typeDescription
queryStringThe text that may contain expressions in the query string syntax to use for search. Required.
allow_leading_wildcardBooleanSpecifies whether and ? are allowed as first characters of a search term. Default is true.
analyze_wildcardBooleanSpecifies whether OpenSearch should attempt to analyze wildcard terms. Default is false.
analyzerStringThe analyzer used to tokenize the query string text. Default is the index-time analyzer specified for the default_field. If no analyzer is specified for the default_field, the analyzer is the default analyzer for the index.
auto_generate_synonyms_phrase_queryBooleanSpecifies whether to create a match phrase query automatically for multi-term synonyms. For example, if you specify ba, batting average as synonyms and search for ba, OpenSearch searches for ba OR “batting average” (if this option is true) or ba OR (batting AND average) (if this option is false). Default is true.
boostFloating-pointBoosts the clause by the given multiplier. Useful for weighing clauses in compound queries. Values in the [0, 1) range decrease relevance, and values greater than 1 increase relevance. Default is 1.
default_fieldStringThe field in which to search if the field is not specified in the query string. Supports wildcards. Defaults to the value specified in the index.query. Default_field index setting. By default, the index.query. Default_field is , which means extract all fields eligible for term query and filter the metadata fields. The extracted fields are combined into a query if the prefix is not specified. Eligible fields do not include nested documents. Searching all eligible fields could be a resource-intensive operation. The indices.query.bool.max_clause_count search setting defines the maximum value for the product of the number of fields and the number of terms that can be queried at one time. The default value for indices.query.bool.max_clause_count is 1,024.
default_operatorStringIf the query string contains multiple search terms, whether all terms need to match (AND) or only one term needs to match (OR) for a document to be considered a match. Valid values are:
- OR: The string to be is interpreted as to OR be
- AND: The string to be is interpreted as to AND be
Default is OR.
enable_position_incrementsBooleanWhen true, resulting queries are aware of position increments. This setting is useful when the removal of stop words leaves an unwanted “gap” between terms. Default is true.
fieldsString arrayThe list of fields to search (for example, “fields”: [“title^4”, “description”]). Supports wildcards. If unspecified, defaults to the index.query. Default_field setting, which defaults to [“*”].
fuzzinessStringThe number of character edits (insert, delete, substitute) that it takes to change one word to another when determining whether a term matched a value. For example, the distance between wined and wind is 1. Valid values are non-negative integers or AUTO. The default, AUTO, chooses a value based on the length of each term and is a good choice for most use cases.
fuzzy_max_expansionsPositive integerThe maximum number of terms to which the query can expand. Fuzzy queries “expand to” a number of matching terms that are within the distance specified in fuzziness. Then OpenSearch tries to match those terms. Default is 50.
fuzzy_transpositionsBooleanSetting fuzzy_transpositions to true (default) adds swaps of adjacent characters to the insert, delete, and substitute operations of the fuzziness option. For example, the distance between wind and wnid is 1 if fuzzy_transpositions is true (swap “n” and “i”) and 2 if it is false (delete “n”, insert “n”). If fuzzy_transpositions is false, rewind and wnid have the same distance (2) from wind, despite the more human-centric opinion that wnid is an obvious typo. The default is a good choice for most use cases.
lenientBooleanSetting lenient to true ignores data type mismatches between the query and the document field. For example, a query string of “8.2” could match a field of type float. Default is false.
max_determinized_statesPositive integerThe maximum number of “states” (a measure of complexity) that Lucene can create for query strings that contain regular expressions (for example, “query”: “/wind.+?/“). Larger numbers allow for queries that use more memory. Default is 10,000.
minimum_should_matchPositive or negative integer, positive or negative percentage, combinationIf the query string contains multiple search terms and you use the or operator, the number of terms that need to match for the document to be considered a match. For example, if minimum_should_match is 2, wind often rising does not match The Wind Rises. If minimum_should_match is 1, it matches. For details, see Minimum should match.
phrase_slopIntegerThe maximum number of words that are allowed between the matched words. If phrase_slop is 2, a maximum of two words is allowed between matched words in a phrase. Transposed words have a slop of 2. Default is 0 (an exact phrase match where matched words must be next to each other).
quote_analyzerStringThe analyzer used to tokenize quoted text in the query string. Overrides the analyzer parameter for quoted text. Default is the search_quote_analyzer specified for the default_field.
quote_field_suffixStringThis option supports searching for exact matches (surrounded with quotation marks) using a different analysis method than non-exact matches use. For example, if quote_field_suffix is .exact and you search for \”lightly\” in the title field, OpenSearch searches for the word lightly in the title.exact field. This second field might use a different type (for example, keyword rather than text) or a different analyzer.
rewriteStringDetermines how OpenSearch rewrites and scores multi-term queries. Valid values are constant_score, scoring_boolean, constant_score_boolean, top_terms_N, top_terms_boost_N, and top_terms_blended_freqs_N. Default is constant_score.
time_zoneStringSpecifies the number of hours to offset the desired time zone from UTC. You need to indicate the time zone offset number if the query string contains a date range. For example, set time_zone”: “-08:00” for a query with a date range such as “query”: “wind rises release_date[2012-01-01 TO 2014-01-01]”). The default time zone format used to specify number of offset hours is UTC.

Query string queries may be internally converted into prefix queries. If search.allow_expensive_queries is set to false, prefix queries are not executed. If index_prefixes is enabled, the search.allow_expensive_queries setting is ignored and an optimized query is built and executed.