Elasticsearch Advanced Search Operations and Configuration
Source Filtering
When Elasticsearch returns search results, it includes all fields stored in _source by default. To retrieve only specific fields, you can filter the _source parameter.
Direct Field Specification
POST /products/_search
{
"_source": ["name", "cost"],
"query": {
"term": {
"cost": 1999
}
}
}
Response:
{
"took": 5,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 1,
"hits": [
{
"_index": "products",
"_type": "item",
"_id": "abc123",
"_score": 1,
"_source": {
"cost": 1999,
"name": "Samsung Phone"
}
}
]
}
}
Using includes and excludes
Alternative syntax using explicit inclusion or exclusion:
POST /products/_search
{
"_source": {
"includes": ["name", "cost"]
},
"query": {
"term": {
"cost": 1999
}
}
}
Equivalent to:
POST /products/_search
{
"_source": {
"excludes": ["thumbnail"]
},
"query": {
"term": {
"cost": 1999
}
}
}
Boolean Queries
The bool query combines other queries using three logical operators:
| Operator | Description |
|---|---|
must |
AND relationship |
must_not |
NOT relationship |
should |
OR relationship |
GET /products/_search
{
"query": {
"bool": {
"must": [
{ "match": { "name": "Samsung" }}
],
"must_not": [
{ "match": { "name": "Tablet" }}
],
"should": [
{ "match": { "name": "Phone" }}
]
}
}
}
Range Queries
Use range queries to find numeric or date values within specified boundaries.
| Operator | Meaning |
|---|---|
gt |
Greater than |
gte |
Greater than or equal |
lt |
Less than |
lte |
Less than or equal |
POST /products/_search
{
"query": {
"range": {
"cost": {
"gte": 1000,
"lt": 3000
}
}
}
}
Fuzzy Queries
Fuzzy matching corrects typos automatically. The search term is matched against indexed documents with a maximum edit distance of 2.
First, add a test document:
POST /products/item/5
{
"name": "iPhone 14",
"thumbnail": "http://images.example.com/iphone14.jpg",
"cost": 7999.00
}
Search with a misspelled term:
POST /products/_search
{
"query": {
"fuzzy": {
"name": "iPhon"
}
}
}
This query successfully returns the iPhone document despite the typo.
Adjustable fuzziness parameter:
POST /products/_search
{
"query": {
"fuzzy": {
"name": {
"value": "iPhonee",
"fuzziness": 2
}
}
}
}
Sorting
Single Field Sort
POST /products/_search
{
"query": {
"match_all": {}
},
"sort": [
{ "cost": { "order": "desc" }}
]
}
Multiple Field Sort
Combine multiple sort criteria—results are sorted by the first field, then by subsequent fields for ties:
POST /products/_search
{
"query": {
"match_all": {}
},
"sort": [
{ "cost": { "order": "desc" }},
{ "_score": { "order": "desc" }}
]
}
Highlighting
Wrap matched terms in custom HTML tags:
POST /products/_search
{
"query": {
"match": {
"name": "Samsung"
}
},
"highlight": {
"pre_tags": ["<mark>"],
"post_tags": ["</mark>"],
"fields": {
"name": {}
}
}
}
Parameters:
pre_tags: Opening tagpost_tags: Closing tagfields: Fields to highlight
Sample response with highlight:
{
"took": 8,
"timed_out": false,
"_shards": { "total": 5, "successful": 5, "skipped": 0, "failed": 0 },
"hits": {
"total": 1,
"max_score": 0.95,
"hits": [
{
"_index": "products",
"_type": "item",
"_id": "xyz789",
"_score": 0.95,
"_source": {
"name": "Samsung Galaxy S23",
"thumbnail": "http://images.example.com/s23.jpg",
"cost": 5499
},
"highlight": {
"name": ["<mark>Samsung</mark> Galaxy S23"]
}
}
]
}
}
Pagination
POST /products/_search
{
"query": {
"match_all": {}
},
"size": 10,
"from": 20
}
size: Number of results per pagefrom: Starting offset index (calculated asfrom = (page - 1) * size)
Practical Examples
Creating Test Data
PUT /merchandise/electronics/1
{
"product_name": "banana",
"description": "yellow fruit",
"price": 25,
"vendor": "ecuador",
"categories": ["tropical", "fruit"]
}
PUT /merchandise/electronics/2
{
"product_name": "apple",
"description": "red or green fruit",
"price": 45,
"vendor": "usa",
"categories": ["fruit", "organic"]
}
PUT /merchandise/electronics/3
{
"product_name": "grape",
"description": "small round fruit",
"price": 12,
"vendor": "italy",
"categories": ["fruit", "wine"]
}
PUT /merchandise/electronics/4
{
"product_name": "pineapple",
"description": "large tropical fruit",
"price": 88,
"vendor": "thailand",
"categories": ["tropical", "exotic"]
}
PUT /merchandise/electronics/5
{
"product_name": "kiwi",
"description": "brown fuzzy fruit",
"price": 30,
"vendor": "newzealand",
"categories": ["organic", "tropical"]
}
PUT /merchandise/electronics/6
{
"product_name": "watermelon",
"description": "large green fruit",
"price": 150,
"vendor": "brazil",
"categories": ["melon", "summer"]
}
Query All Documents
GET /merchandise/electronics/_search
{
"query": {
"match_all": {}
}
}
Filter and Sort
GET /merchandise/electronics/_search
{
"query": {
"match": {
"product_name": "apple"
}
},
"sort": {
"price": {
"order": "asc"
}
}
}
Paginated Results
GET /merchandise/electronics/_search
{
"query": {
"match": {
"product_name": "apple"
}
},
"sort": {
"price": {
"order": "asc"
}
},
"from": 0,
"size": 2
}
Select Specific Fields
GET /merchandise/electronics/_search
{
"query": {
"match_all": {}
},
"_source": ["product_name", "vendor"]
}
Boolean AND Query
GET /merchandise/electronics/_search
{
"query": {
"bool": {
"must": [
{ "match": { "product_name": "apple" }}
]
}
}
}
Multiple AND Conditions
GET /merchandise/electronics/_search
{
"query": {
"bool": {
"must": [
{ "match": { "product_name": "apple" }},
{ "match": { "vendor": "usa" }}
]
}
}
}
Boolean OR Query
GET /merchandise/electronics/_search
{
"query": {
"bool": {
"should": [
{ "match": { "product_name": "apple" }},
{ "match": { "vendor": "italy" }}
]
}
}
}
Boolean NOT Query
GET /merchandise/electronics/_search
{
"query": {
"bool": {
"must_not": [
{ "match": { "product_name": "apple" }},
{ "match": { "vendor": "usa" }}
]
}
}
}
Combined Filter Query
Query documents matching a name with additional range filter:
GET /merchandise/electronics/_search
{
"query": {
"bool": {
"must": [
{ "match": { "product_name": "apple" }}
],
"filter": [
{ "range": { "price": { "gt": 50 }}}
]
}
}
}
Array Field Matching
Search across array fields with space-separated values:
GET /merchandise/electronics/_search
{
"query": {
"match": {
"categories": "organic tropical"
}
}
}
Phrase Match
GET /merchandise/electronics/_search
{
"query": {
"match_phrase": {
"product_name": "apple"
}
}
}
Highlight Results
GET /merchandise/electronics/_search
{
"query": {
"match": {
"product_name": "apple"
}
},
"highlight": {
"pre_tags": ["<strong>"],
"post_tags": ["</strong>"],
"fields": {
"product_name": {}
}
}
}
Aggregations
Basic Aggregation
Calculate average price for top 20 documents:
GET /merchandise/electronics/_search
{
"from": 0,
"size": 20,
"aggs": {
"avg_cost": {
"avg": {
"field": "price"
}
}
}
}
To display only aggregasion results without documents, set size to 0.
Filtered Aggregation
Calculate sum of prices for items matching query and price range:
GET /merchandise/electronics/_search
{
"query": {
"bool": {
"must": [
{ "match": { "product_name": "apple" }}
],
"filter": [
{ "range": { "price": { "gte": 100 }}}
]
}
},
"aggs": {
"total_price": {
"sum": {
"field": "price"
}
}
}
}
Bucket Aggregation with Ranges
GET /merchandise/electronics/_search
{
"size": 0,
"aggs": {
"price_buckets": {
"range": {
"field": "price",
"ranges": [
{ "from": 0, "to": 50 },
{ "from": 50, "to": 100 },
{ "from": 100, "to": 200 }
]
},
"aggs": {
"sum_prices": {
"sum": {
"field": "price"
}
}
}
}
}
}
Output:
{
"took": 9,
"timed_out": false,
"_shards": { "total": 5, "successful": 5, "skipped": 0, "failed": 0 },
"hits": {
"total": 7,
"max_score": 0.0,
"hits": []
},
"aggregations": {
"price_buckets": {
"buckets": [
{
"key": "0.0-50.0",
"from": 0.0,
"to": 50.0,
"doc_count": 3,
"sum_prices": { "value": 67.0 }
},
{
"key": "50.0-100.0",
"from": 50.0,
"to": 100.0,
"doc_count": 2,
"sum_prices": { "value": 133.0 }
},
{
"key": "100.0-200.0",
"from": 100.0,
"to": 200.0,
"doc_count": 2,
"sum_prices": { "value": 238.0 }
}
]
}
}
}
Index Mapping Configuration
Retrieve Existing Mapping
GET /merchandise/_mapping
Create Custom Mapping
The dynamic setting controls how new fields are handled:
| Value | Behavior |
|---|---|
false |
New fields are ignored—no indexing |
true |
New fields are automatically indexed |
strict |
New fields cause an error; must be explicitly defined |
PUT /my_catalog
{
"mappings": {
"category": {
"dynamic": false,
"properties": {
"product_name": {
"type": "text"
},
"quantity": {
"type": "integer"
}
}
}
}
}
copy_to Property
Copy field values to a combined field for unified searching:
PUT /my_catalog2
{
"mappings": {
"record": {
"dynamic": false,
"properties": {
"first": {
"type": "text",
"copy_to": "full_name"
},
"last": {
"type": "text",
"copy_to": "full_name"
},
"full_name": {
"type": "text"
}
}
}
}
}
index Property
Control whether a field is searchable. Default is true:
PUT /my_catalog3
{
"mappings": {
"record": {
"dynamic": false,
"properties": {
"username": {
"type": "text",
"index": true
},
"password": {
"type": "text",
"index": false
}
}
}
}
}
Nested Object Fields
PUT /my_catalog4/record/1
{
"name": "john",
"age": 30,
"location": {
"city": "shanghai",
"phone": "13900000000"
}
}
Query by nested field:
GET /my_catalog4/record/_search
{
"query": {
"match": {
"location.city": "shanghai"
}
}
}
IK Chinese Analyzer
The IK analyzer segments Chinese text into meaningful words rather than individual characters.
Create Index with IK Mapping
PUT /chinese_content
{
"mappings": {
"doc": {
"dynamic": false,
"properties": {
"content": {
"type": "text",
"analyzer": "ik_max_word"
}
}
}
}
}
Index Sample Documents
PUT /chinese_content/doc/1
{
"content": "Today is a beautiful day"
}
PUT /chinese_content/doc/2
{
"content": "Dreams come true"
}
Search with IK Analyzer
GET /chinese_content/_search
{
"query": {
"match": {
"content": "beautiful"
}
}
}
Single character searches fail with IK:
GET /chinese_content/_search
{
"query": {
"match": {
"content": "a"
}
}
}
Compare with Standard Analyzer
PUT /standard_content
{
"mappings": {
"doc": {
"dynamic": false,
"properties": {
"content": {
"type": "text"
}
}
}
}
}
PUT /standard_content/doc/1
{
"content": "Dreams come true"
}
GET /standard_content/_search
{
"query": {
"match": {
"content": "Dreams"
}
}
}
Global Analyzer Configuration
Apply analyzer to all text fields using _all:
PUT /global_analyzer_index/
{
"mappings": {
"doc": {
"_all": {
"analyzer": "ik_smart"
},
"properties": {
"content": {
"type": "text"
}
}
}
}
}
Phrase and Prefix Queries
Match Phrase
GET /standard_content/_search
{
"query": {
"match_phrase": {
"content": "Dreams come"
}
}
}
Match Phrase Prefix
GET /standard_content/_search
{
"query": {
"match_phrase_prefix": {
"content": "Dreams"
}
}
}