How to Use Elasticsearch Query

How to Use Elasticsearch Query Elasticsearch is a powerful, distributed search and analytics engine built on Apache Lucene. It enables near real-time search across massive datasets with high scalability and reliability. At the heart of Elasticsearch’s functionality lies its query system — a sophisticated, flexible mechanism that allows users to retrieve, filter, aggregate, and analyze data with pr

Oct 30, 2025 - 12:39
Oct 30, 2025 - 12:39
 0

How to Use Elasticsearch Query

Elasticsearch is a powerful, distributed search and analytics engine built on Apache Lucene. It enables near real-time search across massive datasets with high scalability and reliability. At the heart of Elasticsearch’s functionality lies its query system — a sophisticated, flexible mechanism that allows users to retrieve, filter, aggregate, and analyze data with precision. Whether you’re building a product search engine, monitoring application logs, or analyzing user behavior patterns, mastering how to use Elasticsearch query is essential for extracting meaningful insights from your data.

Unlike traditional relational databases that rely on SQL for structured queries, Elasticsearch uses a JSON-based query DSL (Domain Specific Language) that supports complex full-text search, boolean logic, fuzzy matching, geospatial queries, and aggregations. This makes it ideal for modern applications that demand fast, relevant, and context-aware results. Understanding how to construct effective Elasticsearch queries not only improves performance but also reduces resource consumption and enhances user experience.

This comprehensive guide walks you through the fundamentals and advanced techniques of using Elasticsearch queries. From basic syntax to real-world applications, you’ll learn how to write queries that are accurate, efficient, and scalable. By the end of this tutorial, you’ll have the confidence to design queries tailored to your specific use case — whether you’re a developer, data analyst, or DevOps engineer.

Step-by-Step Guide

Setting Up Elasticsearch

Before you can begin writing queries, you need a running Elasticsearch instance. The easiest way to get started is by using Docker. If you don’t have Docker installed, download and install it from docker.com. Once installed, run the following command to start Elasticsearch version 8.x:

docker run -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" docker.elastic.co/elasticsearch/elasticsearch:8.12.0

This command starts a single-node Elasticsearch cluster and maps ports 9200 (HTTP) and 9300 (transport). After a few moments, verify the cluster is running by opening your browser or using curl:

curl -X GET "localhost:9200"

You should receive a JSON response containing cluster information such as name, version, and cluster UUID. If you see this, Elasticsearch is ready for queries.

Understanding the Query DSL Structure

Elasticsearch queries are written in JSON using the Query DSL. The basic structure of a query consists of two main components: the query section and optional parameters like size, from, sort, and aggregations.

A minimal query looks like this:

{

"query": {

"match_all": {}

}

}

This query returns all documents in the index. The match_all query is the simplest form and serves as a baseline. More complex queries replace match_all with specific query types such as match, term, bool, or range.

Queries can be sent via HTTP POST to the index endpoint:

curl -X POST "localhost:9200/my_index/_search" -H "Content-Type: application/json" -d '{

"query": {

"match_all": {}

}

}'

Always ensure your request includes the Content-Type: application/json header. The response will include metadata like total hits, took time, and the actual documents under the hits.hits array.

Creating an Index and Adding Sample Data

To practice queries, create an index and populate it with sample data. For this guide, we’ll use a product catalog index:

PUT /products

{

"mappings": {

"properties": {

"name": { "type": "text" },

"description": { "type": "text" },

"price": { "type": "float" },

"category": { "type": "keyword" },

"in_stock": { "type": "boolean" },

"created_at": { "type": "date" }

}

}

}

Now insert sample documents:

POST /products/_bulk

{ "index": {} }

{ "name": "Wireless Headphones", "description": "Noise-cancelling wireless headphones with 30-hour battery life", "price": 199.99, "category": "Electronics", "in_stock": true, "created_at": "2024-01-15" }

{ "index": {} }

{ "name": "Organic Cotton T-Shirt", "description": "100% organic cotton, soft and breathable", "price": 29.99, "category": "Clothing", "in_stock": true, "created_at": "2024-02-10" }

{ "index": {} }

{ "name": "Smart Watch", "description": "Heart rate monitor, GPS, water resistant", "price": 249.99, "category": "Electronics", "in_stock": false, "created_at": "2024-01-22" }

{ "index": {} }

{ "name": "Yoga Mat", "description": "Non-slip eco-friendly yoga mat", "price": 45.50, "category": "Sports", "in_stock": true, "created_at": "2024-03-05" }

After indexing, refresh the index to make documents searchable:

POST /products/_refresh

Basic Query Types

Match Query

The match query is used for full-text search. It analyzes the input text and searches for matching terms across text fields.

{

"query": {

"match": {

"description": "wireless headphones"

}

}

}

This returns documents where the description contains either “wireless” or “headphones” (or both), ranked by relevance. Elasticsearch uses the BM25 algorithm to score results.

Term Query

Unlike match, the term query searches for exact values without analyzing the text. It’s ideal for keyword fields like category or in_stock.

{

"query": {

"term": {

"category": "Electronics"

}

}

}

This returns only documents where the category field exactly matches “Electronics”. Note that “electronics” (lowercase) would not match unless the field was analyzed.

Range Query

Use range to filter numeric or date fields based on boundaries.

{

"query": {

"range": {

"price": {

"gte": 30,

"lte": 200

}

}

}

}

This returns products priced between $30 and $200, inclusive. You can also use gt (greater than), lt (less than), or combine with boost for scoring influence.

Bool Query

The bool query combines multiple queries using logical operators: must, should, must_not, and filter.

{

"query": {

"bool": {

"must": [

{ "match": { "description": "wireless" } }

],

"must_not": [

{ "term": { "category": "Sports" } }

],

"filter": [

{ "range": { "price": { "gte": 50 } } }

]

}

}

}

In this example:

  • must: Documents must contain “wireless” in the description.
  • must_not: Exclude products in the “Sports” category.
  • filter: Only include products priced at $50 or more. Filters are cached and do not affect scoring.

Sorting and Pagination

To sort results, use the sort parameter:

{

"query": {

"match_all": {}

},

"sort": [

{ "price": { "order": "asc" } },

{ "name.keyword": { "order": "asc" } }

]

}

Sorting by name.keyword ensures exact string matching (since name is text type and analyzed). Always use the .keyword sub-field for sorting text fields.

Pagination is handled with from and size:

{

"query": {

"match_all": {}

},

"from": 10,

"size": 10

}

This returns results 11–20. For deep pagination (>10,000 results), use search_after instead of from for better performance.

Using Aggregations

Aggregations allow you to group and summarize data — similar to SQL’s GROUP BY. For example, count products by category:

{

"size": 0,

"aggs": {

"categories": {

"terms": {

"field": "category.keyword"

}

}

}

}

The size: 0 suppresses document results, returning only the aggregation. You can nest aggregations:

{

"size": 0,

"aggs": {

"categories": {

"terms": {

"field": "category.keyword"

},

"aggs": {

"avg_price": {

"avg": {

"field": "price"

}

}

}

}

}

}

This returns each category with its average product price.

Highlighting Search Results

Highlighting helps users identify where their search terms matched in the content:

{

"query": {

"match": {

"description": "wireless"

}

},

"highlight": {

"fields": {

"description": {}

}

}

}

The response includes a highlight section with matched text wrapped in <em> tags by default. Customize the tags with pre_tags and post_tags.

Using Wildcards and Regex

For partial matching, use wildcard or regexp queries. These are slower than term or match queries and should be used sparingly.

{

"query": {

"wildcard": {

"name": "*head*"

}

}

}

This finds any product name containing “head”. For more complex patterns:

{

"query": {

"regexp": {

"name": ".*T-Shirt.*"

}

}

}

Use regexp for pattern-based matching like email or SKU formats.

Querying Nested and Object Fields

If your data contains nested objects, use the nested query. For example, if products have reviews:

PUT /products_with_reviews

{

"mappings": {

"properties": {

"name": { "type": "text" },

"reviews": {

"type": "nested",

"properties": {

"rating": { "type": "integer" },

"comment": { "type": "text" }

}

}

}

}

}

To find products with reviews rating 5:

{

"query": {

"nested": {

"path": "reviews",

"query": {

"term": {

"reviews.rating": 5

}

}

}

}

}

Without nested, Elasticsearch flattens objects and loses relationship context.

Best Practices

Use Filter Context When Possible

Always prefer the filter clause over must when you don’t need relevance scoring. Filters are cached, making them faster for repeated use. For example, filtering by date range or boolean flags should always be in the filter section.

Index Design Matters

Choose the right data types. Use keyword for exact matches and sorting, text for full-text search. Avoid using text for IDs or categories — it wastes memory and slows queries.

Use index aliases to manage schema changes. Instead of querying products_v1, query products and switch the alias when reindexing.

Limit Result Size

Always set a reasonable size limit. The default is 10, but don’t rely on it. For dashboards or APIs, cap at 100–500 results. Use pagination or scroll APIs for bulk exports.

Avoid Deep Pagination

Using from and size beyond 10,000 documents causes performance degradation. Use search_after with a sort value (e.g., _id or timestamp) for cursor-based pagination:

{

"size": 10,

"query": { "match_all": {} },

"sort": [ { "_id": "asc" } ],

"search_after": ["12345"]

}

Use Index Templates for Consistency

Create index templates to enforce consistent mappings across similar indices. For example, all log indices can inherit the same field types and settings:

PUT _index_template/log_template

{

"index_patterns": ["logs-*"],

"template": {

"mappings": {

"properties": {

"message": { "type": "text" },

"timestamp": { "type": "date" },

"level": { "type": "keyword" }

}

}

}

}

Optimize Query Performance

Use explain to understand why a document matched:

GET /products/_search?explain=true

{

"query": { "match": { "name": "headphones" } }

}

Use the Profiler API to analyze slow queries:

GET /products/_search

{

"profile": true,

"query": { "match_all": {} }

}

Monitor slow logs in Elasticsearch config to identify queries taking longer than 500ms.

Cache Frequently Used Queries

Elasticsearch caches filter results automatically. Use cache: true for custom aggregations if needed. Avoid dynamic field names in queries — they prevent caching.

Use Query Validation

Validate queries before deployment:

POST /products/_validate/query?explain=true

{

"query": {

"match": {

"name": "headphones"

}

}

}

This checks syntax and returns parsing errors without executing the query.

Keep Queries Idempotent

Design queries to be reusable and predictable. Avoid hardcoding values — use parameterized queries in your application code. For example, in Python with elasticsearch-py:

query = {

"query": {

"range": {

"price": {

"gte": min_price,

"lte": max_price

}

}

}

}

Tools and Resources

Elasticsearch Kibana

Kibana is the official visualization and query tool for Elasticsearch. Use the Dev Tools console to write, test, and debug queries in real time. It supports syntax highlighting, auto-complete, and response formatting. Access it at http://localhost:5601 after installing the Kibana Docker image.

Elasticsearch SQL

If you’re more comfortable with SQL, Elasticsearch offers a SQL interface. Enable it and query using standard SQL syntax:

POST /_sql?format=txt

{

"query": "SELECT name, price FROM products WHERE price > 50 AND category = 'Electronics'"

}

Useful for analysts migrating from relational databases.

Postman or curl

For API testing, use Postman or command-line curl. Save common queries as templates for reuse. Always use environment variables for host and authentication.

OpenSearch Dashboards

OpenSearch is a fork of Elasticsearch with similar query syntax. If you’re using OpenSearch, most queries remain compatible. Use OpenSearch Dashboards for visualization.

Query Builders

Use client libraries to generate queries programmatically:

  • Python: elasticsearch-py
  • JavaScript: @elastic/elasticsearch
  • Java: RestHighLevelClient or Elasticsearch Java API Client

These libraries help avoid manual JSON errors and support type safety.

Documentation and Community

Always refer to the official Elasticsearch documentation: Elasticsearch Query DSL Guide. The community on Elastic Discuss is active and helpful for troubleshooting.

Monitoring Tools

Use Elasticsearch’s built-in monitoring features or integrate with Prometheus and Grafana to track query latency, throughput, and error rates. Set up alerts for high memory usage or slow queries.

Real Examples

Example 1: E-Commerce Product Search

Scenario: A user searches for “wireless earbuds” and wants results sorted by price, filtered to in-stock items only.

{

"query": {

"bool": {

"must": [

{

"multi_match": {

"query": "wireless earbuds",

"fields": ["name^3", "description"],

"type": "best_fields"

}

}

],

"filter": [

{

"term": {

"in_stock": true

}

}

]

}

},

"sort": [

{

"price": {

"order": "asc"

}

}

],

"size": 20,

"highlight": {

"fields": {

"name": {},

"description": {}

}

}

}

Key features:

  • multi_match with best_fields prioritizes matches in the name field (boosted by ^3).
  • Filter ensures only in-stock items appear.
  • Highlighting helps users see why items matched.

Example 2: Log Analysis for Error Monitoring

Scenario: Find all ERROR logs from the last 24 hours and count them by service.

{

"query": {

"bool": {

"must": [

{

"match": {

"level": "ERROR"

}

}

],

"filter": [

{

"range": {

"timestamp": {

"gte": "now-24h"

}

}

}

]

}

},

"size": 0,

"aggs": {

"services": {

"terms": {

"field": "service.keyword",

"size": 10

}

}

}

}

This helps ops teams identify which services are failing most frequently.

Example 3: User Behavior Analytics

Scenario: Find users who viewed a product and then purchased it within 7 days.

Assume you have two indices: views and purchases, both with user_id and timestamp.

Use a script query to join data via nested fields or use Logstash/Ingest Pipelines to enrich data before indexing. Alternatively, use Kibana Lens or a custom app to correlate events.

For simplicity, assume enriched data exists:

{

"query": {

"bool": {

"must": [

{

"term": {

"event_type": "purchase"

}

}

],

"filter": [

{

"range": {

"purchase_time": {

"gte": "now-7d"

}

}

},

{

"range": {

"view_time": {

"gte": "now-7d",

"lte": "purchase_time"

}

}

}

]

}

},

"aggs": {

"conversion_rate": {

"avg": {

"field": "conversion_score"

}

}

}

}

Example 4: Geospatial Search

Scenario: Find coffee shops within 5 km of a user’s location (latitude: 40.7128, longitude: -74.0060).

First, ensure your index has a geo_point field:

"location": {

"type": "geo_point"

}

Then query:

{

"query": {

"bool": {

"must": [

{

"geo_distance": {

"distance": "5km",

"location": {

"lat": 40.7128,

"lon": -74.0060

}

}

}

]

}

}

}

Combine with aggregations to find the most popular areas.

FAQs

What is the difference between match and term queries?

The match query analyzes input text and searches for matching terms across analyzed fields. It’s used for full-text search. The term query looks for exact matches in non-analyzed fields (like keyword). Use match for descriptions and term for categories or status flags.

Why is my query returning no results?

Common causes include: using term on a text field, mismatched field names, unrefreshed index, or incorrect date format. Use the _validate API and check mappings with GET /index/_mapping.

How do I handle case-insensitive searches?

Use the keyword field with a lowercase analyzer, or use match on a text field with a standard analyzer — it’s case-insensitive by default. For exact case-insensitive matching, create a custom analyzer that lowercases input.

Can I join data from multiple indices like SQL?

Elasticsearch doesn’t support traditional SQL joins. Use nested objects, parent-child relationships, or enrich data during indexing. For complex relationships, consider using a relational database alongside Elasticsearch.

How do I improve query speed?

Use filters instead of queries, avoid wildcard/regex when possible, use appropriate field types, limit result size, and ensure your cluster has enough memory and shards. Monitor slow queries and optimize mappings.

What is the maximum number of results I can retrieve?

By default, Elasticsearch limits results to 10,000. Increase index.max_result_window if needed, but for large datasets, use scroll or search_after APIs.

Can I use Elasticsearch for real-time analytics?

Yes. With its near real-time indexing (typically 1-second latency), aggregations, and fast query engine, Elasticsearch is widely used for real-time dashboards, monitoring systems, and operational analytics.

Is Elasticsearch secure by default?

No. In production, enable security features: TLS encryption, role-based access control, and API keys. Use the Elasticsearch Security module or integrate with LDAP/Active Directory.

Conclusion

Mastering how to use Elasticsearch query transforms raw data into actionable insights. From simple term matches to complex nested aggregations, the Query DSL provides unparalleled flexibility for search and analytics. By following the best practices outlined in this guide — choosing the right query types, optimizing performance, leveraging filters, and validating structure — you’ll build queries that are not only accurate but also efficient and scalable.

Remember: Elasticsearch is not a replacement for relational databases, but a complement. Use it where speed, relevance, and scalability matter most — full-text search, log analysis, real-time dashboards, and recommendation engines. Combine it with the right tools — Kibana, client libraries, and monitoring systems — to create robust, data-driven applications.

As you continue to work with Elasticsearch, experiment with different query combinations, study the profiling output, and contribute to your team’s query library. The more you refine your queries, the more value you extract from your data. Start small, test rigorously, and scale wisely. With practice, you’ll write Elasticsearch queries that are fast, precise, and powerful — turning complexity into clarity.