Exact phrase and proximity search: a step-by-step guide
When users search for "machine learning" in your e-commerce or SaaS platform, they rarely mean results where "machine" appears on page one and "learning" appears on page five. Exact phrase and proximity search: a step-by-step guide gives us the tools to match words that appear together, ensuring that relevant results rank higher than accidental term collisions. Whether you're building a product search engine, a documentation portal, or a content discovery system, mastering phrase and proximity queries can dramatically improve search quality.
Why phrase search matters in production
Before diving into syntax, let's establish why this problem exists. Elasticsearch's standard match query is term-based: it finds documents containing all query terms, regardless of their distance or order. A query for "new york pizza" might return results where "new" is in the title, "york" is buried three paragraphs down, and "pizza" is in a tag. That's technically correct, but practically useless.
Real-world scenarios where phrase search dominates:
- Product search: "iPhone 15 Pro Max" should not match "iPhone MAX 15 Pro" or results mixing iPhone with generic "pro" and "max" keywords.
- Names and entities: "John Smith" is different from "Smith John" in most domains. A recruiter searching for a candidate needs exact matching.
- Titles and headings: Articles titled "The Best SEO Practices" should rank above those mentioning "best," "SEO," and "practices" randomly.
- Compliance and legal: Phrases like "do not resuscitate" or "terms of service" have fixed meanings and must not be scattered across results.
Elasticsearch provides two mechanisms to solve this: the match_phrase query and the slop parameter, which we'll explore step by step.
match_phrase for exact phrases
The match_phrase query is the foundational tool. It finds documents where all query terms appear in the exact order and adjacent to one another (by default, with no words in between). Internally, Elasticsearch uses positional information from the index to verify word sequences.
Here's a simple mapping and query example:
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "standard"
},
"description": {
"type": "text"
}
}
}
}And a basic phrase query:
{
"query": {
"match_phrase": {
"title": "machine learning algorithms"
}
}
}This query will match:
- "Introduction to machine learning algorithms"
- "Advanced machine learning algorithms for production"
- "machine learning algorithms explained"
But it will not match:
- "machine algorithms for learning"
- "algorithms for machine and deep learning"
- "machine learning: algorithms in depth"
The last case is instructive: even though all three terms exist and are in order, the colon breaks the phrase. In Elasticsearch's view, this is a separate sentence or clause, and phrase queries respect token boundaries.
For a real production scenario, consider a travel booking platform indexing hotel names:
PUT /hotels/_doc/1
{
"name": "Grand Hotel New York"
}
PUT /hotels/_doc/2
{
"name": "New York Grand Central Hotel"
}
GET /hotels/_search
{
"query": {
"match_phrase": {
"name": "Grand Hotel New York"
}
}
}This returns only document 1, which is exactly what a user searching for that hotel name expects. Document 2, despite containing all three words, is correctly excluded.
slop allows words in between
In many real-world cases, words legitimately appear in a sequence but not necessarily adjacent. The slop parameter allows a configurable number of position moves to match a phrase. Think of it as a tolerance for word distance.
The slop value defines how many positions each term can be moved to make the phrase match. A slop of 1 allows one word between terms; a slop of 2 allows up to two words, and so on.
Consider a content search where users might search for "Elasticsearch tutorial" but encounter titles like "A Complete Elasticsearch Tutorial for Beginners" or "Elasticsearch: The Definitive Tutorial:"
{
"query": {
"match_phrase": {
"title": {
"query": "Elasticsearch tutorial",
"slop": 5
}
}
}
}With slop: 5, this query matches both:
- "Elasticsearch tutorial" (0 words in between, matched)
- "Elasticsearch practical tutorial" (1 word in between, matched)
- "A Complete Elasticsearch Tutorial for Beginners" (4 words in between, matched)
- "Elasticsearch: The Definitive Tutorial" (2 words in between, matched)
Without slop, only the first result would match. The trade-off is precision: higher slop values cast a wider net but risk including less relevant documents. A typical production heuristic: start with slop: 2 or slop: 3 and tune based on search quality metrics.
A practical implementation in a search-as-you-type scenario for a documentation platform:
POST /docs/_search
{
"query": {
"bool": {
"should": [
{
"match_phrase": {
"content": {
"query": "database indexing",
"slop": 0
}
}
},
{
"match_phrase": {
"content": {
"query": "database indexing",
"slop": 3
}
}
}
]
}
}
}Here, exact phrase matches (slop 0) appear first in the scoring, and slightly relaxed matches provide fallback results. Users get the best of both worlds: precision when available, relevance when needed.
Boost phrase matches in should clauses
A more sophisticated approach uses the bool query to rank phrase matches higher than individual term matches. This is especially powerful for hybrid search strategies where you want exact matches to dominate but still capture partial or scattered-term matches as a safety net.
Consider an e-commerce platform searching product listings:
POST /products/_search
{
"query": {
"bool": {
"should": [
{
"match_phrase": {
"name": {
"query": "iPhone 15 Pro",
"boost": 10
}
}
},
{
"match_phrase": {
"description": {
"query": "iPhone 15 Pro",
"slop": 2,
"boost": 5
}
}
},
{
"match": {
"name": {
"query": "iPhone 15 Pro",
"boost": 2
}
}
}
],
"minimum_should_match": 1
}
}
}This query implements a ranking cascade:
- Exact phrase in name (boost 10): Products literally called "iPhone 15 Pro" rank highest.
- Phrase in description with slight slack (boost 5): Products mentioning the phrase with a word or two in between rank second.
- Individual terms in name (boost 2): Products containing all words (any order) rank last.
The minimum_should_match: 1 ensures at least one clause matches, but the boost weights heavily favor exact phrase matches. This approach significantly improves relevance without hard-filtering results.
For a trading platform indexing financial instruments:
POST /instruments/_search
{
"query": {
"bool": {
"should": [
{
"match_phrase": {
"symbol_name": {
"query": "S&P 500 Index",
"boost": 20
}
}
},
{
"match_phrase": {
"description": {
"query": "S&P 500 Index",
"boost": 5
}
}
}
]
}
}
}Exact matches in symbol names dominate because they're most relevant to traders. The technique scales across domains: news platforms, HR systems, legal document repositories—anywhere exact phrases carry semantic weight.
Great for titles and names
Phrase search shines brightest when indexing structured, meaningful text: product names, article titles, person names, company names, and similar fields where word order and exact sequences matter semantically.
A real-world HR system example:
PUT /candidates/_doc/1
{
"name": "Alice Johnson",
"title": "Senior Software Engineer"
}
PUT /candidates/_doc/2
{
"name": "Johnson Alice",
"title": "Software Engineer Senior"
}
GET /candidates/_search
{
"query": {
"bool": {
"must": [
{
"match_phrase": {
"name": "Alice Johnson"
}
}
]
}
}
}Only document 1 matches. A recruiter searching by name gets the correct candidate, not an accidental name reversal.
For a news aggregation platform:
POST /articles/_search
{
"query": {
"bool": {
"should": [
{
"match_phrase": {
"headline": {
"query": "artificial intelligence revolution",
"boost": 15
}
}
},
{
"match_phrase": {
"headline": {
"query": "artificial intelligence revolution",
"slop": 2,
"boost": 8
}
}
},
{
"match": {
"headline": {
"query": "artificial intelligence revolution",
"boost": 2
}
}
}
]
}
}
}Articles with exact headline matches appear at the top, dramatically improving editorial search quality and user experience.
Common mistakes
Mistake 1: Using match_phrase for unstructured text without understanding its limitations. Phrase queries are strict; they break on sentence boundaries and punctuation variations. For loosely structured content like blog post bodies, pair phrase queries with fuzziness or slop to avoid false negatives. Test your queries against real data before deploying.
Mistake 2: Setting slop too high. A slop of 10 or higher effectively turns your phrase query into a loose term query with minimal positional benefit. Start low (slop: 2–3) and measure recall and precision before increasing. Higher slop also impacts query performance.
Mistake 3: Forgetting to boost phrase matches appropriately. If you use phrase queries within a bool query, omitting boost values means phrase matches score the same as loose matches. Always explicitly boost exact phrases to reflect their semantic importance.
Mistake 4: Indexing without positional data. Phrase queries rely on term positions stored during indexing. If you use a custom analyzer that strips or reorders positions, phrase queries fail silently. Verify your analyzer settings: standard, english, and most built-in analyzers preserve positions by default.
Mistake 5: Testing only with happy paths. Phrase queries are sensitive to tokenization, case folding, and stemming. A search for "machine learning" might fail if your analyzer stems terms to "machin" and "learn," making positional matching impossible. Always test with real user queries and edge cases.
Key takeaways
- match_phrase finds exact word sequences and is the baseline for phrase search. Use it when word order matters.
- slop tolerates intervening words and balances precision with recall. Start with slop 2–3 and measure results.
- Boost phrase matches in bool queries to rank them higher than scattered-term matches, implementing a relevance cascade.
- Phrase search excels for structured fields like names, titles, and product names where semantic meaning depends on exact sequences.
- Common pitfalls include high slop values, missing boost weights, and analyzer misconfigurations. Test thoroughly before production deployment.
- Combine phrase queries with standard match queries in should clauses to provide both precision and recall in a single search request.






Comments
Loading comments…