Terms query

Use the terms query to search for multiple terms in the same field. For example, the following query searches for lines with the IDs 61809 and 61810:

  1. GET shakespeare/_search
  2. {
  3. "query": {
  4. "terms": {
  5. "line_id": [
  6. "61809",
  7. "61810"
  8. ]
  9. }
  10. }
  11. }

copy

A document is returned if it matches any of the terms in the array.

By default, the maximum number of terms allowed in a terms query is 65,536. To change the maximum number of terms, update the index.max_terms_count setting.

The ability to highlight results for terms queries may not be guaranteed, depending on the highlighter type and the number of terms in the query.

Parameters

The query accepts the following parameters. All parameters are optional.

ParameterData typeDescription
<field>StringThe field in which to search. A document is returned in the results only if its field value exactly matches at least one term, with the correct spacing and capitalization.
boostFloating-pointA floating-point value that specifies the weight of this field toward the relevance score. Values above 1.0 increase the field’s relevance. Values between 0.0 and 1.0 decrease the field’s relevance. Default is 1.0.
value_typeStringSpecifies the types of values used for filtering. Valid values are default and bitmap. If omitted, the value defaults to default.

Terms lookup

Terms lookup retrieves the field values of a single document and uses them as search terms. You can use terms lookup to search for a large number of terms.

To use terms lookup, you must enable the _source mapping field because terms lookup fetches values from a document. The _source field is enabled by default.

Terms lookup tries to fetch the document field values from a shard on a local data node. Thus, using an index with a single primary shard that has full replicas on all applicable data nodes reduces network traffic.

Example

As an example, create an index that contains student data, mapping student_id as a keyword:

  1. PUT students
  2. {
  3. "mappings": {
  4. "properties": {
  5. "student_id": { "type": "keyword" }
  6. }
  7. }
  8. }

copy

Next, index three documents that correspond to students:

  1. PUT students/_doc/1
  2. {
  3. "name": "Jane Doe",
  4. "student_id" : "111"
  5. }

copy

  1. PUT students/_doc/2
  2. {
  3. "name": "Mary Major",
  4. "student_id" : "222"
  5. }

copy

  1. PUT students/_doc/3
  2. {
  3. "name": "John Doe",
  4. "student_id" : "333"
  5. }

copy

Create a separate index that contains class information, including the class name and an array of student IDs corresponding to the students enrolled in the class:

  1. PUT classes/_doc/101
  2. {
  3. "name": "CS101",
  4. "enrolled" : ["111" , "222"]
  5. }

copy

To search for students enrolled in the CS101 class, specify the document ID of the document that corresponds to the class, the index of that document, and the path of the field in which the terms are located:

  1. GET students/_search
  2. {
  3. "query": {
  4. "terms": {
  5. "student_id": {
  6. "index": "classes",
  7. "id": "101",
  8. "path": "enrolled"
  9. }
  10. }
  11. }
  12. }

copy

The response contains the documents in the students index for every student whose ID matches one of the values in the enrolled array:

  1. {
  2. "took": 13,
  3. "timed_out": false,
  4. "_shards": {
  5. "total": 1,
  6. "successful": 1,
  7. "skipped": 0,
  8. "failed": 0
  9. },
  10. "hits": {
  11. "total": {
  12. "value": 2,
  13. "relation": "eq"
  14. },
  15. "max_score": 1,
  16. "hits": [
  17. {
  18. "_index": "students",
  19. "_id": "1",
  20. "_score": 1,
  21. "_source": {
  22. "name": "Jane Doe",
  23. "student_id": "111"
  24. }
  25. },
  26. {
  27. "_index": "students",
  28. "_id": "2",
  29. "_score": 1,
  30. "_source": {
  31. "name": "Mary Major",
  32. "student_id": "222"
  33. }
  34. }
  35. ]
  36. }
  37. }

Example: Nested fields

The second example demonstrates querying nested fields. Consider an index with the following document:

  1. PUT classes/_doc/102
  2. {
  3. "name": "CS102",
  4. "enrolled_students" : {
  5. "id_list" : ["111" , "333"]
  6. }
  7. }

copy

To search for students enrolled in CS102, use the dot path notation to specify the full path to the field in the path parameter:

  1. GET students/_search
  2. {
  3. "query": {
  4. "terms": {
  5. "student_id": {
  6. "index": "classes",
  7. "id": "102",
  8. "path": "enrolled_students.id_list"
  9. }
  10. }
  11. }
  12. }

copy

The response contains the matching documents:

  1. {
  2. "took": 18,
  3. "timed_out": false,
  4. "_shards": {
  5. "total": 1,
  6. "successful": 1,
  7. "skipped": 0,
  8. "failed": 0
  9. },
  10. "hits": {
  11. "total": {
  12. "value": 2,
  13. "relation": "eq"
  14. },
  15. "max_score": 1,
  16. "hits": [
  17. {
  18. "_index": "students",
  19. "_id": "1",
  20. "_score": 1,
  21. "_source": {
  22. "name": "Jane Doe",
  23. "student_id": "111"
  24. }
  25. },
  26. {
  27. "_index": "students",
  28. "_id": "3",
  29. "_score": 1,
  30. "_source": {
  31. "name": "John Doe",
  32. "student_id": "333"
  33. }
  34. }
  35. ]
  36. }
  37. }

Parameters

The following table lists the terms lookup parameters.

ParameterData typeDescription
indexStringThe name of the index in which to fetch field values. Required.
idStringThe document ID of the document from which to fetch field values. Required.
pathStringThe name of the field from which to fetch field values. Specify nested fields using dot path notation. Required.
routingStringCustom routing value of the document from which to fetch field values. Optional. Required if a custom routing value was provided when the document was indexed.
boostFloating-pointA floating-point value that specifies the weight of this field toward the relevance score. Values above 1.0 increase the field’s relevance. Values between 0.0 and 1.0 decrease the field’s relevance. Default is 1.0.

Bitmap filtering

Introduced 2.17

The terms query can filter for multiple terms simultaneously. However, when the number of terms in the input filter increases to a large value (around 10,000), the resulting network and memory overhead can become significant, making the query inefficient. In such cases, consider encoding your large terms filter using a roaring bitmap for more efficient filtering.

The following example assumes that you have two indexes: a products index, which contains all the products sold by a company, and a customers index, which stores filters representing customers who own specific products.

First, create a products index and map product_id as a keyword:

  1. PUT /products
  2. {
  3. "mappings": {
  4. "properties": {
  5. "product_id": { "type": "keyword" }
  6. }
  7. }
  8. }

copy

Next, index three documents that correspond to products:

  1. PUT students/_doc/1
  2. {
  3. "name": "Product 1",
  4. "product_id" : "111"
  5. }

copy

  1. PUT students/_doc/2
  2. {
  3. "name": "Product 2",
  4. "product_id" : "222"
  5. }

copy

  1. PUT students/_doc/3
  2. {
  3. "name": "Product 3",
  4. "product_id" : "333"
  5. }

copy

To store customer bitmap filters, you’ll create a customer_filter binary field in the customers index. Specify store as true to store the field:

  1. PUT /customers
  2. {
  3. "mappings": {
  4. "properties": {
  5. "customer_filter": {
  6. "type": "binary",
  7. "store": true
  8. }
  9. }
  10. }
  11. }

copy

For each customer, you need to generate a bitmap that represents the product IDs of the products the customer owns. This bitmap effectively encodes the filter criteria for that customer. In this example, you’ll create a terms filter for a customer whose ID is customer123 and who owns products 111, 222, and 333.

To encode a terms filter for the customer, first create a roaring bitmap for the filter. This example creates a bitmap using the [PyRoaringBitMap] library, so first run pip install pyroaring to install the library. Then serialize the bitmap and encode it using a Base64 encoding scheme:

  1. from pyroaring import BitMap
  2. import base64
  3. # Create a bitmap, serialize it into a byte string, and encode into Base64
  4. bm = BitMap([111, 222, 333]) # product ids owned by a customer
  5. encoded = base64.b64encode(BitMap.serialize(bm))
  6. # Convert the Base64-encoded bytes to a string for storage or transmission
  7. encoded_bm_str = encoded.decode('utf-8')
  8. # Print the encoded bitmap
  9. print(f"Encoded Bitmap: {encoded_bm_str}")

copy

Next, index the customer filter into the customers index. The document ID for the filter is the same as the ID for the corresponding customer (in this example, customer123). The customer_filter field contains the bitmap you generated for this customer:

  1. POST customers/_doc/customer123
  2. {
  3. "customer_filter": "OjAAAAEAAAAAAAIAEAAAAG8A3gBNAQ=="
  4. }

copy

Now you can run a terms query on the products index to look up a specific customer in the customers index. Because you’re looking up a stored field instead of _source, set store to true. In the value_type field, specify the data type of the terms input as bitmap:

  1. POST /products/_search
  2. {
  3. "query": {
  4. "terms": {
  5. "product_id": {
  6. "index": "customers",
  7. "id": "customer123",
  8. "path": "customer_filter",
  9. "store": true
  10. },
  11. "value_type": "bitmap"
  12. }
  13. }
  14. }

copy

You can also directly pass the bitmap to the terms query. In this example, the product_id field contains the customer filter bitmap for the customer whose ID is customer123:

  1. POST /products/_search
  2. {
  3. "query": {
  4. "terms": {
  5. "product_id": "OjAAAAEAAAAAAAIAEAAAAG8A3gBNAQ==",
  6. "value_type": "bitmap"
  7. }
  8. }
  9. }

copy