DEV Community

Cover image for How to Use Elasticsearch APIs ?
Preecha
Preecha

Posted on

How to Use Elasticsearch APIs ?

TL;DR

Elasticsearch APIs power search and analytics at scale. Index JSON documents, query them with the Elasticsearch Query DSL, and use aggregations for analytics. Authenticate with API keys or basic auth. Use Apidog to validate mappings, test search queries, and debug aggregations before deploying to production clusters.

Try Apidog today

Introduction

Elasticsearch is a distributed search and analytics engine for structured text, logs, metrics, and other document-oriented data.

Common use cases include:

  • Full-text search in applications
  • Log analysis and debugging
  • Real-time analytics dashboards
  • Security and network-event analysis

Elasticsearch is part of the ELK stack—Elasticsearch, Logstash, and Kibana—but you can use its REST APIs directly without Logstash.

💡 If you are building search features or log-analysis workflows, Apidog helps you test queries, validate mappings, debug aggregations, save search templates, and share them with your team.

Test Elasticsearch APIs with Apidog - free

By the end of this guide, you will be able to:

  • Index and manage documents
  • Write Elasticsearch DSL search queries
  • Use aggregations for analytics
  • Configure mappings and analyzers
  • Monitor cluster health

Getting started

Run Elasticsearch locally

Run Elasticsearch in a single-node Docker container:

docker run -p 9200:9200 \
  -e "discovery.type=single-node" \
  elasticsearch:8.11.0
Enter fullscreen mode Exit fullscreen mode

Alternatively, download Elasticsearch from Elastic.

Verify the installation

Send a request to the root endpoint:

curl -X GET "http://localhost:9200"
Enter fullscreen mode Exit fullscreen mode

Example response:

{
  "name": "elasticsearch-1",
  "cluster_name": "elasticsearch",
  "cluster_uuid": "abc123",
  "version": {
    "number": "8.11.0",
    "build_flavor": "default"
  },
  "tagline": "You know, for search"
}
Enter fullscreen mode Exit fullscreen mode

Authenticate requests

Elasticsearch 8.x requires authentication by default. Use basic authentication when testing locally:

curl -X GET "http://localhost:9200/_cluster/health" \
  -u elastic:your_password
Enter fullscreen mode Exit fullscreen mode

You can also use API keys created in Kibana or through the Elasticsearch API.

Indices and documents

An index is a collection of documents. A document is a JSON object stored in that index.

Create an index

Create a products index with explicit settings and mappings:

curl -X PUT "http://localhost:9200/products" \
  -u elastic:your_password \
  -H "Content-Type: application/json" \
  -d '{
    "settings": {
      "number_of_shards": 1,
      "number_of_replicas": 0
    },
    "mappings": {
      "properties": {
        "name": { "type": "text" },
        "price": { "type": "float" },
        "category": { "type": "keyword" },
        "in_stock": { "type": "boolean" },
        "created_at": { "type": "date" }
      }
    }
  }'
Enter fullscreen mode Exit fullscreen mode

Use text for analyzed full-text search fields and keyword for exact-match filters, sorting, and aggregations.

Index a document

Add a product document:

curl -X POST "http://localhost:9200/products/_doc" \
  -u elastic:your_password \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Wireless Headphones",
    "price": 79.99,
    "category": "electronics",
    "in_stock": true,
    "created_at": "2026-03-24T10:00:00Z"
  }'
Enter fullscreen mode Exit fullscreen mode

Example response:

{
  "_index": "products",
  "_id": "abc123",
  "_version": 1,
  "result": "created",
  "_seq_no": 0,
  "_primary_term": 1
}
Enter fullscreen mode Exit fullscreen mode

Save the returned _id if you need to retrieve, replace, or delete this document later.

Get a document

Retrieve a document by ID:

curl -X GET "http://localhost:9200/products/_doc/abc123" \
  -u elastic:your_password
Enter fullscreen mode Exit fullscreen mode

Update a document

Replace the document at a known ID:

curl -X PUT "http://localhost:9200/products/_doc/abc123" \
  -u elastic:your_password \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Wireless Headphones Pro",
    "price": 99.99,
    "category": "electronics",
    "in_stock": true,
    "created_at": "2026-03-24T10:00:00Z"
  }'
Enter fullscreen mode Exit fullscreen mode

Delete a document

Delete a document by ID:

curl -X DELETE "http://localhost:9200/products/_doc/abc123" \
  -u elastic:your_password
Enter fullscreen mode Exit fullscreen mode

Bulk operations

Use the _bulk endpoint to index multiple documents efficiently. Bulk request bodies use newline-delimited JSON (NDJSON):

curl -X POST "http://localhost:9200/products/_bulk" \
  -u elastic:your_password \
  -H "Content-Type: application/x-ndjson" \
  -d '{"index":{"_id":"1"}}
{"name":"Product A","price":10.99,"category":"books","in_stock":true}
{"index":{"_id":"2"}}
{"name":"Product B","price":20.99,"category":"electronics","in_stock":false}
'
Enter fullscreen mode Exit fullscreen mode

Each document needs an action line such as index, followed by its source document.

Search queries

Send search requests to the /_search endpoint.

Basic search

Search for documents whose name matches headphones:

curl -X GET "http://localhost:9200/products/_search" \
  -u elastic:your_password \
  -H "Content-Type: application/json" \
  -d '{
    "query": {
      "match": {
        "name": "headphones"
      }
    }
  }'
Enter fullscreen mode Exit fullscreen mode

Use match for analyzed text fields.

Bool queries

Use a bool query to combine full-text matching with exact filters:

{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "headphones"
          }
        }
      ],
      "filter": [
        {
          "term": {
            "category": "electronics"
          }
        },
        {
          "range": {
            "price": {
              "lte": 100
            }
          }
        },
        {
          "term": {
            "in_stock": true
          }
        }
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Use filter for non-scoring constraints such as categories, price ranges, and booleans.

Full-text search with scoring

Search across multiple fields and boost the name field:

{
  "query": {
    "multi_match": {
      "query": "wireless audio headphones",
      "fields": ["name^2", "description"],
      "type": "best_fields",
      "fuzziness": "AUTO"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

The ^2 suffix gives name double weight in score calculation.

Phrase search

Find documents containing an exact phrase:

{
  "query": {
    "match_phrase": {
      "description": "noise canceling"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Wildcard and regex-style matching

Use a wildcard query when you need pattern matching:

{
  "query": {
    "wildcard": {
      "name": "*headphone*"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Sort results

Sort products by ascending price, then by descending relevance score:

{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "price": "asc"
    },
    {
      "_score": "desc"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Paginate results

Use from and size for offset-based pagination:

{
  "from": 20,
  "size": 10,
  "query": {
    "match_all": {}
  }
}
Enter fullscreen mode Exit fullscreen mode

This request returns 10 documents starting at result 21.

Aggregations

Aggregations calculate summary statistics across matching documents.

Calculate average price by category

Group products by category, then calculate average, minimum, and maximum prices for each group:

curl -X GET "http://localhost:9200/products/_search" \
  -u elastic:your_password \
  -H "Content-Type: application/json" \
  -d '{
    "size": 0,
    "aggs": {
      "by_category": {
        "terms": {
          "field": "category"
        },
        "aggs": {
          "avg_price": {
            "avg": {
              "field": "price"
            }
          },
          "min_price": {
            "min": {
              "field": "price"
            }
          },
          "max_price": {
            "max": {
              "field": "price"
            }
          }
        }
      }
    }
  }'
Enter fullscreen mode Exit fullscreen mode

Set "size": 0 when you only need aggregation results and do not need matching documents.

Build a price histogram

Bucket products into price intervals:

{
  "size": 0,
  "aggs": {
    "price_histogram": {
      "histogram": {
        "field": "price",
        "interval": 25
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Group data by date

Use a date histogram for time-series analytics:

{
  "size": 0,
  "aggs": {
    "sales_over_time": {
      "date_histogram": {
        "field": "created_at",
        "calendar_interval": "month"
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Count unique values

Count unique product categories with a cardinality aggregation:

{
  "size": 0,
  "aggs": {
    "unique_categories": {
      "cardinality": {
        "field": "category"
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Mappings and analyzers

Mappings define field types and determine how Elasticsearch indexes and searches data.

Choose the right field type

Type Use for
text Full-text search, analyzed values
keyword Exact values, filtering, sorting
integer, float Numbers
boolean True or false values
date Dates and times
object Nested JSON objects
nested Arrays of objects while maintaining relationships
geo_point Latitude and longitude coordinates

Create a custom analyzer

Use a custom analyzer for specialized text processing, such as autocomplete:

{
  "settings": {
    "analysis": {
      "analyzer": {
        "autocomplete": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": ["lowercase", "autocomplete_filter"]
        }
      },
      "filter": {
        "autocomplete_filter": {
          "type": "edge_ngram",
          "min_gram": 2,
          "max_gram": 20
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "name": {
        "type": "text",
        "analyzer": "autocomplete",
        "search_analyzer": "standard"
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

This configuration indexes prefixes for autocomplete while using the standard analyzer when users search.

Cluster management

Check cluster health

curl -X GET "http://localhost:9200/_cluster/health"
Enter fullscreen mode Exit fullscreen mode

Example response:

{
  "cluster_name": "elasticsearch",
  "status": "green",
  "number_of_nodes": 3,
  "active_primary_shards": 25
}
Enter fullscreen mode Exit fullscreen mode

Cluster status meanings:

  • green: All shards are allocated.
  • yellow: Replica shards are not allocated, which is common on a single-node cluster.
  • red: One or more primary shards are missing.

View index statistics

curl -X GET "http://localhost:9200/_cat/indices?v"
Enter fullscreen mode Exit fullscreen mode

View node statistics

curl -X GET "http://localhost:9200/_nodes/stats"
Enter fullscreen mode Exit fullscreen mode

Clear caches

curl -X POST "http://localhost:9200/_cache/clear"
Enter fullscreen mode Exit fullscreen mode

Testing with Apidog

Elasticsearch queries can become complex quickly. Test requests, responses, and environments before using them in production.

Image

1. Save reusable queries

Store parameterized search templates in Apidog:

{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "{{search_field}}": "{{search_term}}"
          }
        }
      ],
      "filter": [
        {
          "range": {
            "{{price_field}}": {
              "lte": "{{max_price}}"
            }
          }
        }
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Use variables to test the same query against different fields, terms, and limits.

2. Validate responses

Add tests to confirm that searches and aggregations return expected data:

pm.test("Search returns results", () => {
  const response = pm.response.json()
  pm.expect(response.hits.total.value).to.be.above(0)
})

pm.test("Aggregations present", () => {
  const response = pm.response.json()
  pm.expect(response.aggregations).to.exist
})
Enter fullscreen mode Exit fullscreen mode

3. Separate local and production environments

Store hostnames and credentials as environment variables:

# Local
ES_HOST: http://localhost:9200
ES_USER: elastic
ES_PASSWORD: your_password

# Production
ES_HOST: https://search.yourcompany.com
ES_API_KEY: prod_api_key
Enter fullscreen mode Exit fullscreen mode

Test Elasticsearch APIs with Apidog - free

Common errors and fixes

403 Forbidden

Cause: Authentication failed or the authenticated user lacks required permissions.

Fix: Verify credentials and confirm that the API key has permissions for the target index.

404 index_not_found_exception

Cause: The target index does not exist.

Fix: Create the index first. Auto-creation is enabled by default, but it is not recommended for production.

circuit_breaking_exception

Cause: The query uses too much memory.

Fix: Reduce the size parameter, simplify the query, and add filters to reduce the result set.

search_phase_execution_exception

Cause: The query syntax is invalid.

Fix: Validate the JSON body. Common causes include missing quotes and incorrect field paths.

Alternatives and comparisons

Feature Elasticsearch OpenSearch Meilisearch Typesense
Setup Self-hosted Self-hosted Single binary Single binary
Search quality Excellent Good Excellent Good
Learning curve Steep Steep Easy Easy
Scalability Excellent Excellent Good Good
Cloud offering Elastic Cloud OpenSearch Serverless Meilisearch Cloud Typesense Cloud

Elasticsearch has the broadest feature set and community. Meilisearch and Typesense are simpler options for basic search requirements.

Real-world use cases

E-commerce search

A retail site indexes 100,000 products. Users search product names and descriptions, then filter by category, price range, and availability. Autocomplete suggests products while users type.

Application logs

A DevOps team ships logs to Elasticsearch through Filebeat. Engineers search by service, severity, and time range, while dashboards display error rates and response times.

Security analytics

A security team indexes network logs, searches suspicious IP addresses, visualizes traffic patterns, and alerts on anomalies detected through aggregations.

Wrapping up

You have learned how to:

  • Index JSON documents
  • Query data with Elasticsearch DSL
  • Use aggregations for analytics
  • Configure mappings for search behavior
  • Monitor cluster health

Next steps:

  1. Run Elasticsearch locally.
  2. Create an index with explicit mappings.
  3. Index test documents.
  4. Write and test search queries.
  5. Add aggregations for analytics.

Test Elasticsearch APIs with Apidog - free

FAQ

What is the difference between Elasticsearch and Solr?

Both are Lucene-based search engines. Elasticsearch has a stronger distributed design and API experience. Solr has more enterprise features. Most new projects choose Elasticsearch.

How do I handle special characters in search?

Escape special characters with a backslash:

()[]{}:^\"\\+-!~*?|
Enter fullscreen mode Exit fullscreen mode

You can also use simple_query_string, which is more forgiving.

What is a shard?

Shards are pieces of an index. Each shard is a Lucene index. Primary shards handle writes, while replica shards provide read scaling and fault tolerance.

How many shards should I create?

A common guideline is 20–50 GB per shard. Start with one primary shard and add replicas. Only increase the number of primary shards when needed because you cannot decrease them later.

Can I change mappings after indexing?

Partially. You can add new fields, but changing an existing field type requires reindexing the data. Use index templates to manage mappings consistently.

What is the _routing parameter?

_routing routes documents to specific shards based on a field value. The default is _id. Use routing when queries always filter by a specific field, such as user_id, to improve performance.

How do I handle time-based data?

Use date-based indices, such as:

logs-2026.03.24
Enter fullscreen mode Exit fullscreen mode

This makes it easier to delete old data by removing entire indices and can improve query performance by searching fewer indices.

Top comments (0)