The Percolator in Elasticsearch

The Percolator in Elasticsearch

How Elasticsearch turns search upside down: instead of asking which documents match a query, it asks which saved queries match a brand-new document.

Imagine a property website with two million visitors who have each saved a search. One person wants a two-bedroom flat in Leeds under nine hundred pounds a month. Another wants a house with a garden near a good school. A third wants any studio close to a train station. Every day, thousands of new listings arrive. When a new flat is posted, the site must work out, within moments, which of those two million saved searches it matches, so that the right people get an email or a phone alert.

The obvious approach is painful. You could run all two million saved searches every time a listing arrives, which would bury your servers. Or you could run each visitor’s search once every few minutes and compare the results with the last run, which is slow, wasteful and still late. Neither feels right, because the problem is the wrong way round. You are not looking for documents that match one query. You have one document and want to know which queries it matches.

Elasticsearch has a built-in feature made for exactly this backwards question. It is called the percolator. This guide explains it from zero. Every new word is explained the first time it appears, and each idea builds on the last. By the end, you will know what the percolator is, how it works inside, where it shines, what it costs and which traps to avoid.

1What Is the Percolator?

We start with the simple idea behind the name, and then look at how Elasticsearch makes that idea real.

Search Normally Works One Way

Elasticsearch is a search engine. It stores items called documents, such as products, articles or listings, inside containers called indices. When someone runs a query, which is a description of what they are looking for, Elasticsearch finds the documents that match it. In this normal direction, the documents are stored and the queries are temporary. A query arrives, gets answered and is forgotten.

The Percolator Flips It

The percolator turns this around. It lets you store queries as if they were documents. Later, when a new document arrives, you hand it to Elasticsearch and ask, “Which of my stored queries match this?” Elasticsearch replies with the list of matching queries. The queries are permanent, and the incoming document is the temporary visitor.

The name comes from the coffee percolator, where hot water passes through a basket of coffee grounds. Here, a document passes through a large collection of stored queries, and the ones that “catch” it are the matches.

Everyday Analogy

Think of a mailroom in a big company. Each employee has left a note at the desk saying what kind of mail they want to hear about: “anything from the tax office”, “parcels from the lab supplier”, “letters mentioning the merger”. When a new letter arrives, the clerk does not go to each employee and ask. The clerk reads the letter once and checks it against the pile of notes to see whose notes it fits. The notes are stored queries. The letter is the incoming document. The clerk is the percolator.

i
Definition

The percolator is an Elasticsearch feature that lets you store queries in an index, using a special field type, and then run a document against them to find out which stored queries would match that document. It is often called reverse search.

1
special field type that holds a stored query
2
roles swapped: queries are the data, the document is the question
Millions
of stored queries can be checked per document with the right design

What the Percolator Is Not

The percolator does not watch your data by itself. It does not send emails or push alerts. It only answers one question when you ask it: “Which stored queries match this document?” Your own application must ask that question for each new document and then act on the answer. The percolator is also not a machine-learning classifier that guesses. It matches exactly according to the rules in the stored queries. And it is not meant for everyday searching, where ordinary queries against stored documents are the right tool.

2Why We Need Reverse Search

To understand why the percolator exists, look at what goes wrong when people try to solve matching problems with normal search.

The Two Naive Solutions

The first naive solution is to run every saved search for every new document. If you have two million saved searches and five thousand new documents an hour, that is ten billion query runs an hour. Even if each run is tiny, the total is enormous, and almost all of the runs will find nothing.

The second naive solution is polling, which means running each saved search on a schedule, say every ten minutes, and checking for anything new. Polling wastes effort, because most runs find no change. It also adds delay, because a person may wait up to ten minutes for an alert. Shorten the schedule to reduce delay and the cost climbs even higher.

Cost

Too Many Queries

Running every saved search against every new document multiplies two big numbers, and the result overwhelms even large clusters.

Delay

Late Alerts

Polling on a schedule means an alert may arrive minutes after the matching item appeared, and popular items may be gone by then.

Waste

Empty Runs

Most polled searches find nothing new. The cluster does real work to learn that nothing happened.

Complexity

Custom Matching Code

Writing your own matching engine in application code means rebuilding text analysis, ranges and geography rules that Elasticsearch already knows.

Consistency

Different Rules in Two Places

If saved searches are matched by custom code while normal search uses Elasticsearch, the two can disagree about what “matches” means.

Growth

Cost That Scales Badly

Doubling users and doubling documents quadruples the naive work. The problem gets worse faster than the business grows.

Everyday Analogy

Suppose a newspaper wants to tell readers when a story about their favorite topic appears. One way is to have an assistant call every reader every ten minutes and ask, “Has a story about your topic appeared?” That wastes thousands of phone calls. The smarter way is for the editor to read each new story once, check a list of reader interests and phone only the readers whose interests match. The percolator is that smarter editor.

Why Not Build It Yourself?

A team could write its own matcher, but real queries are complicated. They involve words that must be broken into pieces and reduced to their roots, numbers within ranges, locations within distances, combinations with “and” and “or”, and exclusions. Elasticsearch already implements all this for ordinary search. The percolator reuses the same query language and the same text analysis, so a saved query means exactly the same thing whether it is used in search or in reverse search.

Normal search asks which documents fit this question. The percolator asks which questions fit this document.

3Core Concepts You Need First

A handful of words appear in every percolator discussion. Learn them here and the later chapters will feel easy.

Word 1

Stored Query

A query saved inside an index instead of being run once. It is the “note” that describes what someone wants to be told about.

Word 2

Percolator Field

A special field type that holds a stored query. Its name is chosen by you, and it lives in an index next to any other fields you want to keep with the query.

Word 3

Percolate Query

The query you run to find matching stored queries. You give it a document, and it returns the stored queries that match.

Word 4

Candidate Document

The incoming document you are testing. It is not stored. It is only passed through the stored queries.

Word 5

Mapping

The description of an index’s fields and their types. The percolator index needs a mapping for the fields used in stored queries and in candidate documents.

Word 6

Query Extraction

At the time a query is stored, Elasticsearch pulls out key terms from it and saves them, so it can later find likely matches quickly.

Word 7

Candidate Selection

A fast first step that narrows millions of stored queries to the few that could possibly match the incoming document.

Word 8

Verification

A second, exact step in which each remaining candidate query is really run against the document to confirm the match.

Word 9

Metadata Filter

A normal filter on extra fields stored beside the query, such as the subscriber’s region, used to skip queries that cannot apply.

Word 10

Analyzer

The text-processing recipe that breaks text into searchable terms. The same analyzer is used for stored queries and incoming documents, so they line up.

The Chain of Ideas

Here is how these words fit in one sentence. You store queries in a percolator field, in an index with a proper mapping. At storage time, Elasticsearch performs query extraction. Later, your application sends a candidate document inside a percolate query. Elasticsearch does candidate selection to narrow the field, then verification to confirm matches, and returns the matching stored queries. Read the chain twice, and the rest of the guide will feel familiar.

Everyday Analogy

Consider an airport security desk with a list of watch notes. A quick glance at a passenger’s name and destination rules out almost every note. Only a few notes even come close, so the officer reads those few in full to confirm. The quick glance is candidate selection, and reading the few notes in full is verification. Without the quick glance, the officer would have to read thousands of notes for every passenger, and the line would stretch out the door.

*
Good to Know

Stored queries use the same query language as ordinary search. If you can write a query that finds documents, you can store it as a percolator query. There is no second language to learn.

4Forward Search Versus Reverse Search

Putting the two directions side by side makes the percolator’s role very clear.

flowchart LR
    subgraph FWD["Forward search: ordinary Elasticsearch"]
        Q1["One query arrives"] --> IDX1["Many stored documents"]
        IDX1 --> R1["Matching documents returned"]
    end
    subgraph REV["Reverse search: the percolator"]
        D2["One document arrives"] --> IDX2["Many stored queries"]
        IDX2 --> R2["Matching queries returned"]
    end
Figure 1: Forward search stores documents and tests queries. Reverse search stores queries and tests documents.
QuestionForward SearchReverse Search With the Percolator
What is stored?DocumentsQueries
What arrives at run time?A queryA document
What comes back?Matching documentsMatching stored queries
Typical questionWhich flats match my search?Whose saved searches match this new flat?
Typical size of the stored sideMillions of documentsThousands to millions of queries
Typical useFinding, browsing and analyzingAlerting, tagging and routing

Pull and Push

Another way to see the difference is through the words pull and push. Ordinary search is pull: a person goes to the search box and pulls the results they want. The percolator supports push: when something new arrives, it tells you who should be pushed a message about it. Most alerting systems are push systems, which is why the percolator fits them so well.

Everyday Analogy

Visiting a library and asking the librarian to find books about gardening is a pull. Signing up with the library to be phoned whenever a new gardening book arrives is a push. Both need a catalog of books and a list of interests. The first uses the catalog as the stored side. The second uses the list of interests as the stored side, and that is what the percolator holds.

!
Watch Out

The push happens in your own application, not inside Elasticsearch. The percolator answers “who matches?” and your code decides how to notify them. Teams sometimes expect Elasticsearch to send the notifications by itself, and they are surprised when nothing happens.

5Architecture and Components

Let us look at the parts that work together in a percolator setup, from the people who save searches to the people who receive alerts.

The Parts of the System

Front Door

API Gateway and Load Balancer

The gateway is the single entrance for requests from web and mobile apps, handling login checks and rate limits. The load balancer spreads requests across the application servers so that none is overloaded.

Application

Subscription Service

Your code that lets people create, edit and delete saved searches. It checks each request and writes the resulting stored query into the percolator index.

Application

Matching Service

Your code that receives each new document and asks Elasticsearch which stored queries match. It then hands the answer to the notification side.

Elasticsearch

Percolator Index

An index with a percolator field for stored queries, plus fields that describe the queries, such as the owner, region and status.

Elasticsearch

Document Index

The ordinary index that holds the real documents, such as listings. It is separate from the percolator index and serves normal search.

Delivery

Queue and Notification Service

A message queue holds the matches. A notification service sends emails, push messages or webhooks to the people whose queries matched.

flowchart TD
    U["People on web and mobile apps"] --> G["API Gateway"]
    G --> LB["Load Balancer"]
    LB --> SUB["Subscription Service: save, edit, delete searches"]
    SUB --> PIDX["Elasticsearch percolator index: stored queries"]
    SRC["New documents from publishers or data pipeline"] --> ING["Ingestion Service"]
    ING --> DIDX["Elasticsearch document index: real documents"]
    ING --> MATCH["Matching Service"]
    MATCH --> PIDX
    PIDX --> MATCH
    MATCH --> Q["Message queue"]
    Q --> NOTIF["Notification Service"]
    NOTIF --> U
    MON["Monitoring: latency, match counts, errors"] --> MATCH
    MON --> PIDX
Figure 2: A typical percolator setup. Saved searches flow into the percolator index, and new documents flow through it to find who should be notified.

Reading the Diagram

Look at the top-left first. People use web and mobile apps, and their requests pass through the gateway and load balancer to the subscription service. This service writes each saved search into the percolator index as a stored query. That is the “left side” of the system, which is quiet and changes only when people edit their searches.

Now look at the right side. New documents come from publishers or a data pipeline. The ingestion service stores each one in the ordinary document index, and also passes it to the matching service. The matching service asks the percolator index which stored queries match, receives a list of matches, and places them on a message queue. The notification service picks them up and sends the alerts to the right people. Monitoring watches the matching service and the percolator index, since they carry the real-time part of the system.

i
Design Note

The message queue is not part of the percolator, but it is a very wise addition. It separates finding the matches from sending the messages, so a slow email provider cannot slow down matching, and a burst of matches cannot overwhelm the notification service.

6Internal Working: Life of One Percolate Request

Follow one new document from the moment it arrives to the moment the list of matching queries comes back.

sequenceDiagram
    participant PUB as Publisher
    participant MS as Matching Service
    participant CN as Coordinating node
    participant SH as Percolator index shards
    participant ML as Notification queue
    PUB->>MS: New document arrives
    MS->>CN: Percolate query with the document
    CN->>SH: Send the request to every shard
    SH->>SH: Build a tiny in-memory index of the document
    SH->>SH: Candidate selection using extracted terms
    SH->>SH: Verify each candidate query against the document
    SH-->>CN: Matching stored queries
    CN-->>MS: Merged list of matches
    MS->>ML: Queue one alert per match
Figure 3: One percolate request. Each shard narrows and verifies on its own, and the coordinating node merges the answers.
1

A document arrives

A publisher posts a new flat, article or event. Your matching service receives it and prepares a percolate query that carries the document inside it.

2

The request reaches the cluster

Elasticsearch accepts the request on a coordinating node. Since stored queries are spread across shards, the coordinating node forwards the request to every shard of the percolator index.

3

Each shard builds a tiny index

On each shard, the incoming document is analyzed with the analyzers from the mapping and loaded into a very small in-memory index. This index holds only this one document, and it disappears when the work ends.

4

Candidates are selected

The shard looks at the terms in the document and quickly finds stored queries whose key terms could possibly be satisfied. Most stored queries are ruled out here, without being run at all.

5

Candidates are verified

For each remaining candidate, the shard runs the real stored query against the tiny in-memory index. If the query finds the document, it is a true match.

6

Matches return as ordinary hits

Each matching stored query comes back as a normal search hit, along with the extra fields stored next to it, such as the owner’s identifier. The coordinating node merges the hits from all shards.

7

Your application acts

The matching service reads the list, looks at the owner identifiers, and places an alert for each one on the queue. Elasticsearch’s part is finished.

Why the Tiny Index Is So Clever

The trick of building a small in-memory index for the document lets Elasticsearch reuse its entire ordinary search machinery. A stored query does not know or care that the document is temporary. It runs against the tiny index exactly as it would against a large one. This is why any query that works in normal search can, with a few exceptions, work as a stored query too.

Everyday Analogy

Imagine a teacher marking exam papers with a marking guide made of many separate questions. Instead of inventing a new marking system for every student, the teacher puts the student’s answer sheet on the same desk, in the same format as all the others, and applies the same marking guide. The tiny in-memory index is that desk: it makes the temporary document look like any other document so that the standard guide can be used.

7Storing Queries: The Percolator Field and Mapping

Before any document can be percolated, the queries must be stored in an index that is prepared for them. This chapter explains the preparation.

The Percolator Field Type

Every field in an Elasticsearch index has a type, such as text, number, date or location. The percolator adds one more type, also called percolator. A field of this type holds a whole query. You choose its name, for example “query”, and then each document in the index carries one stored query in that field. In effect, the percolator index is a table of saved searches, where each row is one saved query with some extra columns.

The Index Needs Two Kinds of Fields

The percolator index must contain the percolator field, and it must also describe every field that the stored queries and the candidate documents will use. Suppose stored queries talk about “title”, “price”, “city” and “bedrooms”. Then the index mapping must define those four fields with the correct types, even though the index does not store real listings. The mapping is the shared vocabulary that lets stored queries and incoming documents understand each other.

Everyday Analogy

Think of a form for saved requests at a library. The form has a box for the request itself, which is like the percolator field. It also needs the same categories that books are filed under, such as author, subject and year, so the request can refer to them. If the request mentions “subject” but the library’s filing system has no such category, nobody can tell what the request means.

Extra Fields Beside the Query

You can add ordinary fields next to the percolator field. They describe the stored query and are very useful. Typical examples are the identifier of the person who owns the saved search, the region it applies to, whether it is active, when it was created and the language of the alerts. These extra fields are normal, searchable fields, so you can filter and sort by them.

Field

Query Field

The percolator field that holds the stored query. One per stored query document.

Field

Owner Identifier

Tells your application whom to notify when this query matches.

Field

Region or Category

Lets you filter out queries that cannot apply to the incoming document, before any matching is done.

Field

Status and Timestamps

Lets you disable a saved search without deleting it, and lets you find old or unused ones later.

Fields Must Exist First

The fields used inside a stored query must already be defined in the mapping when the query is stored. Elasticsearch checks the query at that moment, and it will reject a query that refers to unknown fields. This is helpful, because it catches typing mistakes early, but it also means that adding a new searchable field requires updating the mapping first, before anyone can save a query that uses it.

!
Watch Out

Stored queries are analyzed and prepared at the moment they are saved, using the mapping as it is at that time. If you later change how a field is analyzed, existing stored queries do not update themselves. You will need to save them again, which means re-indexing the percolator index. Plan your text analysis carefully before you store millions of queries.

*
Practical Tip

Keep the percolator index separate from your ordinary document index. The two have different sizes, different traffic and different tuning needs, and a separate index lets you scale, back up and rebuild each one on its own.

8Candidate Selection: How the Percolator Stays Fast

The secret to handling millions of stored queries is that the percolator almost never runs most of them. This chapter explains how.

The Problem It Solves

Imagine one million stored queries and one incoming document. If Elasticsearch had to run every query against the document, it would perform one million query runs for a single document. Even at a tiny cost each, this adds up to a large delay, and it would be hopeless at thousands of documents per minute. Yet in almost every real system, only a handful of the stored queries could possibly match any given document.

Step One: Extract Terms When the Query Is Stored

When a query is saved, Elasticsearch studies it. It looks for the terms that must be present in a document for the query to have any chance of matching. For a simple query that requires the word “garden”, the key term is “garden”. For a query that requires both “leeds” and “balcony”, Elasticsearch picks terms that a matching document is certain to contain. It stores these extracted terms in hidden fields next to the query.

Step Two: Look Up Candidates Fast

When a document arrives, Elasticsearch collects the terms that appear in it and asks one fast question of the hidden fields: “Which stored queries have key terms that this document actually contains?” This uses the same fast lookup structure that ordinary search uses, so it is quick even with millions of entries. Only the queries that pass this test become candidates.

Step Three: Verify the Candidates

The candidate list is a shortlist, not the final answer. A query might have the right key term but fail on another condition, such as a price range. So each candidate is run for real against the tiny in-memory index of the document. Only those that truly match are returned.

flowchart TD
    S["Stored queries: extracted key terms saved at storage time"] --> C1
    D["Incoming document"] --> T["Collect the document's terms"]
    T --> C1["Fast lookup: which stored queries share terms with the document"]
    C1 --> CAND["Shortlist of candidate queries"]
    CAND --> V["Run each candidate query against the in-memory copy of the document"]
    V --> M["Confirmed matches"]
    V --> X["Rejected candidates"]
Figure 4: Two-phase matching. A fast lookup produces a shortlist, and exact verification produces the final matches.
Everyday Analogy

Think of a lost-property office with a huge wall of tickets, each describing what a person lost. A worker holds up a found umbrella. Instead of reading every ticket, the worker scans the wall for tickets that mention “umbrella”, which is very quick. That gives twenty tickets. Then the worker reads only those twenty in full to check the color, size and place, and finds two real matches. The quick scan is candidate selection, and reading the twenty is verification.

When Selection Cannot Help

Some queries cannot be narrowed by key terms. A query that matches everything has no term to look up, so it is always a candidate and must always be verified. Certain other shapes, such as some negations or unusual combinations, also give little to extract. A percolator index full of such queries loses the benefit of candidate selection, and performance falls toward the naive “run everything” case.

Good

Specific Word Queries

Queries that require particular words give sharp key terms. Most candidates are ruled out immediately.

Good

Combinations With “And”

Queries where several conditions must all hold give Elasticsearch a choice of terms and narrow the shortlist well.

Weak

Match-Everything Queries

Nothing to look up. Always verified against every document.

Weak

Very Broad Queries

Queries on extremely common words become candidates for almost every document, so the shortlist stays long.

*
Practical Tip

Encourage, or require, users to make saved searches specific. A saved search such as “any flat anywhere” will be a candidate for every single document and will slow every percolate request. A saved search such as “two bedrooms, Leeds, under 900” is a sharp query that is easy to rule out for most documents.

9Percolating Documents: One, Many or Already Stored

There are several ways to hand documents to the percolator. Each fits a different situation.

One Document Inline

The simplest way is to include the document inside the percolate query. You name the percolator field and give the document’s contents. Elasticsearch builds the tiny in-memory index and returns matching stored queries. This is what a real-time matching service does for a single new document, for example when a new listing is posted.

Many Documents Together

You can also give a list of documents in the same request. Elasticsearch then builds a small in-memory index holding all of them and matches each stored query against the group. In the response, each hit reports which of your documents matched, using a position number called a slot. Percolating documents in batches is usually much more efficient than one at a time, because the fixed costs of the request are shared. It is a natural fit for systems that receive documents in bursts.

Everyday Analogy

A postal worker sorting letters could take each letter to the mailbox wall, one by one, walking back and forth. Or the worker could carry a stack of letters to the wall once, and sort them all in one trip. The stack takes some care to keep track of, since you need to remember which letter goes where. The slot number is the way the percolator remembers which letter matched which box.

An Already Stored Document

If the document already lives in an ordinary index, you do not need to send its contents again. You can point the percolate query at the index and the document’s identifier, and Elasticsearch fetches the document and runs it against the stored queries. This helps when you index first and percolate afterward, or when you want to re-check old documents against newly created queries.

Way To PercolateYou ProvideBest ForWatch For
One inline documentThe document’s contentsReal-time matching of each new item as it arrivesMany small requests add up in overhead
Several inline documentsA list of documentsBursts, batches and backfillsVery large batches use more memory on each shard
An existing stored documentAn index name and identifierRe-checking stored documents against new queriesThe document must exist and be readable when you ask

What Comes Back

The response looks like an ordinary search response. Each hit is a stored query, complete with the extra fields stored beside it, such as the owner identifier and region. When you percolated several documents, each hit also says which documents matched. The score on each hit is not a measure of how good the document is. It reflects how the stored query was matched, and most systems ignore it and simply treat the list of hits as a list of matches.

i
Design Note

Choose the batch size by testing. A batch of a few dozen documents is often a good starting point. Too small wastes overhead, and too large can make each request slow and memory-hungry. Measure with your real queries and documents.

10Filtering, Combining and Highlighting

The percolate query is a normal query, which means it can be combined with other queries. This makes real systems much faster and much more useful.

Filter Before You Percolate

Stored queries come with extra fields such as region, category and status. You can combine the percolate query with ordinary filters on those fields. For example, “only stored queries that are active and belong to the Leeds region.” Elasticsearch applies these cheap filters first, so the expensive matching runs on far fewer stored queries. In systems with regions, languages or customers, this single habit can reduce the work by an order of magnitude.

Everyday Analogy

A librarian with a huge box of reader requests receives a new book about local history in Leeds. Instead of checking every request, the librarian first takes out only the requests from people living in Leeds who have not paused their membership. The box is now much smaller, and checking each request is quick. Filters by extra fields are that first sorting step.

Combining Several Percolate Queries

A single request can hold more than one percolate query, joined with “and”, “or” or “not” logic. A common use is to percolate several different kinds of documents at once, or to run two different percolator fields against the same document. Each part can be given a name, and the response reports which named part matched, which helps you tell the reasons for a match apart.

Highlighting the Reason

Sometimes it is useful to know not just that a stored query matched, but why. The percolator supports highlighting, which marks the exact words in the incoming document that caused the match. For an alert email, this lets you show “Your search for ‘garden’ matched this listing, which says ‘a private garden and terrace’.” It is a small feature that makes alerts feel far more intelligent and trustworthy.

Tool 1

Metadata Filters

Filter stored queries by region, status or tenant to shrink the work before matching begins.

Tool 2

Boolean Combinations

Join percolate queries with other conditions to express more complex needs in a single request.

Tool 3

Named Parts

Give each percolate query a name so that the response tells you which one matched.

Tool 4

Highlighting

Show which words in the document caused each match, for clearer alerts and easier debugging.

Tool 5

Sorting and Paging

Order matches by a field such as creation date, and page through very large result lists.

Tool 6

Field Selection

Return only the fields you need, such as the owner identifier, to keep responses small and fast.

*
Practical Tip

A match that is popular may return thousands of stored queries for a single document, for example when a very attractive listing matches many saved searches. Ask for only the fields you need, and page through results, or the response itself can become a performance problem.

11What Kinds of Queries Can Be Stored?

Almost every query type works, but a few do not. Knowing the limits early avoids surprises.

The Broad Rule

A stored query can use the normal query language: words and phrases, exact values, numeric and date ranges, geographic distances, combinations with “and”, “or” and “not”, and many more. The core rule is that the query must be answerable using only the information inside the incoming document and the mapping. A query that needs to look at some other document, or at the current clock, cannot be prepared ahead of time.

Query KindWorks as a Stored Query?Why
Full-text word and phrase queriesYesThey depend only on the document’s text and the analyzers
Exact-value and range queriesYesThey compare the document’s fields with fixed values
Geographic distance queriesYesThey compare a location in the document with a fixed point
Boolean combinationsYesThey simply combine the queries above
Queries that join to other documentsNoThey need to look at other documents, but the percolator sees only one temporary document
Queries that look up values elsewhere at run timeNoThey need a lookup outside the incoming document
Ranges based on the current timeNot acceptedThe meaning of “now” would be frozen at storage time, not at matching time

The Trouble With “Now”

People often want alerts such as “listings posted within the last day.” A stored query cannot say “within the last day” using the current time, because the stored query is prepared once, when it is saved, and would keep using that moment forever. The usual solution is to move the time logic into your application. Since the percolator sees each document as it arrives, “just posted” is already true for every document you percolate. If you need age rules, add a field to the document such as “hours since posting” at percolate time, or apply the rule in your own code afterward.

Everyday Analogy

Suppose you write on a note, “Tell me about deliveries arriving in the next two hours,” and pin it to a board. The words “next two hours” make sense on the day you write the note, but the note stays on the board for months. Two hours from when? The note cannot hold a moving clock. A better note says what you truly care about, such as “Tell me about deliveries of flowers,” and the clerk applies the timing when the delivery arrives.

Fields Must Match Between Queries and Documents

A stored query and an incoming document must use the same field names with the same meanings. If a stored query talks about “price” as a number, but the incoming document sends “price” as text like “nine hundred pounds”, the match will fail or be rejected. Agree on one clear document shape, and validate both queries and documents against it.

!
Watch Out

Because supported and unsupported query types can change between versions, check Elastic’s documentation for your version before designing around a specific type. Test any unusual query shape by actually storing it and percolating a sample document.

12Use Case One: Alerts and Saved Searches

The most common use of the percolator is the alert: “tell me when something new matches what I am looking for.”

The Alert Pipeline

flowchart LR
    NEW["New listing posted"] --> ING["Ingestion Service"]
    ING --> IDX["Store in the document index"]
    ING --> PERC["Percolate against stored searches"]
    PERC --> HITS["List of matching saved searches"]
    HITS --> DEDUP["Remove duplicates and respect quiet hours"]
    DEDUP --> QUEUE["Alert queue"]
    QUEUE --> EMAIL["Email"]
    QUEUE --> PUSH["Mobile push"]
    QUEUE --> HOOK["Webhook to partner system"]
Figure 5: An alert pipeline. The percolator finds the matching saved searches, and the rest of the system decides how and when to notify.

The flow is simple. A new listing arrives and is stored in the ordinary index so that it appears in normal search. At the same moment, it is percolated against all the saved searches. The list of matches is cleaned up, for example by removing duplicates and respecting quiet hours, and placed on a queue. Separate workers turn queue items into emails, phone notifications or messages to partner systems.

Everyday Analogy

A travel-deal website is like a fisherman’s net cast over a stream of arriving deals. Each traveler has left a small hook describing the trip they want. When a deal floats past, it snags on some hooks and slips by others. The percolator decides which hooks catch which deals, and the notification workers pull each snagged deal back to the traveler.

Designing Good Alerts

  • Be timely. Percolate as soon as a document is indexed. The value of an alert falls quickly with time, especially for scarce items.
  • Be specific. Ask users for enough detail that their queries are precise. Vague queries create noisy alerts and slow matching.
  • Avoid duplicates. If a document is edited several times, decide whether each edit should alert again. Keep a record of which alerts were sent.
  • Respect limits. Give users a way to control the number and frequency of alerts, and offer a daily digest as an alternative to instant messages.
  • Explain the match. Use highlighting to show why the alert was sent, which makes alerts feel useful and not random.

Example: A Job Board

A job board lets candidates save searches such as “data engineer, remote, Python”. Each saved search becomes a stored query with the candidate’s identifier and location preference beside it. When a new job is posted, the job board percolates it and gets back the list of candidates whose searches match. Within seconds, matching candidates receive an email with the job title highlighted against their search words.

*
Practical Tip

Store the same query in your ordinary user interface as a saved search, so that when someone clicks the alert, the page shows the results of the same query. Keeping one source of truth for “what this saved search means” avoids confusing differences between alerts and search pages.

13Use Case Two: Classification and Tagging

The percolator can also sort and label documents using rules that people write, without any machine learning.

Rules as Stored Queries

Imagine a news site that wants to label each incoming article with topics such as “football”, “elections” or “technology”. Editors write rules for each topic: the words and phrases that signal it. Each rule is stored as a query. When an article arrives, the percolator returns which topic rules matched, and the system attaches those topics as tags. Adding a new topic requires only saving a new query. No new code is needed.

Everyday Analogy

A warehouse sorting line has a row of labeled chutes. Each chute has a rule, such as “parcels marked fragile” or “parcels going to the north region”. As each parcel travels down the belt, the sorter checks which rules apply and drops it into the right chutes. The rules are stored queries, and the belt is your stream of documents.

Why Use Rules Instead of Machine Learning?

Machine learning classifiers can be powerful, but they have costs: they need training data, they can be hard to explain, and they can change behavior when retrained. Rules are transparent, quick to change and easy to audit. For classification tasks where the categories are clear and the signals are keywords, or combinations of fields, rules stored in the percolator are often simpler and more trustworthy. Many teams also combine both: rules for the clear cases and a model for the fuzzy ones.

ApproachStrengthsWeaknesses
Percolator rulesTransparent, instantly editable, explainable, no training neededRules must be written and maintained by people; misses subtle cases
Machine learning classifierLearns subtle patterns from examplesNeeds labeled data, harder to explain, changes when retrained
Both togetherRules cover clear cases, models help with the restMore parts to build and maintain

Typical Tagging Tasks

Media

Topic Labels

Tag articles and videos by topic so they appear on the right pages and in the right newsletters.

Support

Ticket Routing

Match incoming support requests to teams by keywords, product names and customer tier.

Commerce

Product Categories

Assign products to categories and collections based on their titles, brands and attributes.

Content

Editorial Flags

Mark content that needs review, such as mentions of restricted topics or sensitive words.

*
Practical Tip

Keep a small set of example documents for each rule, and test every new or edited rule against them before it goes live. A rule that quietly matches too much can tag thousands of documents wrongly before anybody notices.

14Use Case Three: Monitoring, Compliance and Routing

The percolator is also a general “rules on a stream” engine. Any time you have many rules and a flow of incoming events, it can help.

Watching Streams of Events

Operations teams handle streams of logs, messages and events. Each team may care about different patterns: a specific error code, a mention of a certain customer, a payment above a limit in a certain country. Instead of building one big program with all rules hard-wired, the team stores each rule as a query. As events flow past, the percolator reports which rules fired, and the system triggers the right action for each.

Compliance and Safety Checks

Regulated industries must check communications and content for banned or sensitive language, or for patterns of concern. Compliance staff maintain a list of rules. Each new message is percolated, and any that match are flagged for review. Because the rules are ordinary stored queries, compliance staff can add or change them quickly when regulations change, without waiting for a software release.

Everyday Analogy

A building’s security desk has a card listing who should be stopped or reported, and why. A guard watches each visitor walk past and checks the card. When the rules change, the desk simply replaces the card. The guard’s routine stays the same. The percolator index is the card, and it can be updated in seconds.

Routing Work to the Right Place

The same idea helps route work. An insurance company might route each incoming claim to a specialist team, based on rules about the type of loss, the region and the amount. A logistics company might route shipment events to the right customer dashboards. Each routing rule is a stored query, and the percolator says which routes apply to each event.

Example: Payment Screening

A payment company keeps rules such as “transfers above a set amount to certain countries” and “several small transfers to the same account within a short window.” Each rule is a stored query. As transactions stream in, the percolator flags the ones that match, and flagged items go to analysts. When new rules are agreed, the compliance team adds them to the percolator index, and they apply to the next transaction.

!
Watch Out

The percolator judges one document at a time. Rules that need to look at patterns over time, such as “three failed logins in five minutes”, cannot be answered by the percolator alone, because it does not remember earlier documents. Use a stream-processing tool or an alerting feature for time-window logic, and use the percolator for per-document rules.

15The Percolator Versus Other Approaches

Several other tools can seem to solve the same problem. Comparing them shows where the percolator fits best.

ApproachHow It WorksBest ForMain Limit
PercolatorStores queries and matches each new document against themMany user-defined rules with a stream of new documentsJudges one document at a time, and you build the notification side
Polling saved searchesRuns each saved search on a scheduleA small number of saved searches with relaxed timingSlow, wasteful and expensive as the number of searches grows
Scheduled alerting rulesRuns a query on a timer and checks conditions on the resultsOperational alerts on trends, thresholds and time windowsRuns by schedule, so it is not per-document and not suited to millions of user rules
Enrichment at ingestLooks up matching reference records while indexing a documentAdding fields from a reference table by exact value, range or locationNot for full-text rules or arbitrary query logic
Custom matching codeYour own program tests rules against each documentVery special rules that queries cannot expressYou must rebuild analysis, ranges and geography yourself
Machine learning classifierA trained model labels each documentFuzzy categories learned from examplesNeeds data, and is harder to explain

Alerting Features Versus the Percolator

Elasticsearch and Kibana also have alerting features. They usually run a search on a schedule and fire an action if the results meet a condition, such as “more than a hundred errors in the last five minutes.” That is perfect for operational monitoring. The percolator is different: it reacts to each new document, and it can hold millions of separate rules belonging to millions of users. Think of alerting rules as a smoke detector that watches a room over time, and the percolator as a doorman who checks each guest against a guest list as they enter.

Enrichment Versus Percolation

An enrich feature at ingest time adds information to a document by looking up matching reference data, for example adding a region name based on a postcode. It answers “what extra data belongs to this document?” The percolator answers “which rules does this document satisfy?” They can work together: enrich the document first so that it has the fields that rules need, then percolate it.

*
How to Decide

Ask two questions. Do I have many separate rules, perhaps belonging to different users? Do I need to react to each new document? If both answers are yes, the percolator is a strong fit. If you only have a few operational conditions over time windows, scheduled alerting rules may be simpler.

16Text Analysis and the Percolator

Text search depends on how words are broken up and simplified. For the percolator, this process must be identical on both sides.

What Analysis Does

Before text can be searched, Elasticsearch runs it through an analyzer. An analyzer splits text into words, converts them to lower case, and may reduce them to a root form, so that “running”, “runs” and “ran” can be treated as related. It may also remove tiny words such as “the”. This is what lets a search for “garden flat” find a listing that says “Flats with Gardens”.

Both Sides Use the Same Recipe

In the percolator, the stored query and the incoming document are both analyzed using the mapping of the percolator index. Because they share the same recipe, their terms line up. If the recipe changed in the middle, the stored queries would hold terms produced by the old recipe, while new documents would be broken up by the new one. Matches could silently disappear.

Everyday Analogy

Two people agree to meet at a place they both call “the old market”. If one calls it by that name and the other switched to calling it “Market Square”, they may go to different places and never meet. Stored queries and documents must use the same naming rules, or they will miss each other.

Changing Analyzers Later

Extracted terms and prepared queries are created when a query is stored. If you change the analyzer for a field, you must store the queries again so they are prepared with the new recipe. In practice, this means creating a new percolator index with the new mapping, copying the queries into it, and switching your application to the new index. Plan this as a normal migration, with testing and a rollback plan.

Rule 1

Decide Early

Choose analyzers before storing large numbers of queries. Changing them later means a rebuild.

Rule 2

Test With Real Text

Try real queries and real documents. Simple examples hide surprises such as plurals, accents and punctuation.

Rule 3

Keep Versions

Keep the source of every stored query in your own database too, so the percolator index can be rebuilt at any time.

Rule 4

Match the Search Index

Where possible, use the same analysis as your ordinary search index, so saved searches behave as they do on the results page.

!
Watch Out

A silent mismatch of analysis is one of the hardest percolator bugs to find. Nothing fails. Alerts simply stop arriving for some kinds of words. Keep a small suite of known query and document pairs that must match, and run it after every mapping change.

17Performance and Scalability

The percolator can handle very large collections of stored queries, but only if you understand where the time goes.

Where the Time Goes

Each percolate request has a few parts. First, the request travels to every shard of the percolator index. Second, each shard builds a tiny in-memory index of the incoming document. Third, each shard performs candidate selection over its stored queries. Fourth, each shard verifies the candidates by running them. Finally, the results travel back and are merged. The biggest variable is usually the number of candidates that need verification, and the cost of each one.

Lever 1

Metadata Filters

Filtering stored queries by region, tenant or status before matching is the single most effective speed-up in most systems.

Lever 2

Query Specificity

Specific queries have sharp key terms and are ruled out early. Vague queries become candidates for many documents.

Lever 3

Query Cost

Cheap queries verify fast. Expensive ones, such as wildcards on common prefixes, slow every request in which they are candidates.

Lever 4

Batching

Percolating several documents in one request shares the fixed overhead and raises throughput.

Lever 5

Shard Count

More shards add parallelism, but every shard repeats the work of building the in-memory index, so too many shards waste effort.

Lever 6

Replicas and Hardware

Replicas let more percolate requests run at once. Fast processors matter most, since the work is mainly CPU-bound.

Parallel Work Across Shards

Stored queries are spread across shards, and each shard works on its own share at the same time. If one shard holds a quarter of the stored queries, it does about a quarter of the matching. This is why percolator indices scale well as they grow: adding shards and nodes spreads the stored queries thinner. However, the setup cost per shard, such as building the tiny index, is repeated on every shard. Choose a shard count that keeps each shard busy with a meaningful number of queries and no more.

Everyday Analogy

Imagine a team of clerks each holding a portion of the guest-list cards. When a guest arrives, every clerk checks their own cards at once. That makes the check fast. But each clerk must first take a look at the guest, which takes a few seconds. If you have fifty clerks, each with only ten cards, the looking takes longer than the checking. There is a sweet spot between too few clerks, who are overloaded, and too many, who spend all their time looking.

Throughput Versus Latency

Latency is how long one request takes. Throughput is how many requests or documents can be handled per second. A system that percolates each document individually may have low latency for each but limited throughput. A system that batches documents raises throughput but adds a little waiting time for each document while the batch fills. Choose based on your needs: instant alerts need small batches, and overnight backfills can use large ones.

!
Watch Out

Test with your real queries. Systems tested with a few hundred neat queries can behave very differently with a million messy user-written ones. One heavy query type that accounts for one percent of stored queries can dominate the time of every request if it is a candidate for most documents.

Example: Filtering to Speed Up Matching

A classifieds site has a million stored queries across twenty countries. Each stored query has a country field. Percolating a new advertisement against all of them takes about 300 milliseconds. The team adds a filter so that only stored queries for the advertisement’s country are considered. That cuts the pool to about fifty thousand, and the time falls to around 25 milliseconds. Nothing else changed.

18Data Flow and the Life of a Stored Query

A stored query passes through a series of stages, from the moment a person saves a search to the day it is removed.

flowchart LR
    C["Created by a person"] --> V["Validated by your service"]
    V --> S["Stored in the percolator index"]
    S --> X["Terms extracted and indexed"]
    X --> A["Active: matched against new documents"]
    A --> E["Edited: replaced by a new version"]
    E --> V
    A --> P["Paused: status set to inactive"]
    P --> A
    A --> D["Deleted or expired"]
    P --> D
Figure 6: The life of a stored query. Most of its life is spent in the active state.
Stage 1

Created

A person fills in a form or clicks “save this search”. Your service turns that into a query written in the Elasticsearch query language.

Stage 2

Validated

Your service checks that the query is allowed: only supported query types, sensible size, no expensive patterns, and within the user’s limits.

Stage 3

Stored

The query is written into the percolator index, with extra fields such as owner, region and status.

Stage 4

Extracted

Elasticsearch analyzes the query and saves its key terms for candidate selection. This happens automatically at storage time.

Stage 5

Active

The query takes part in every percolate request that its filters allow, and produces matches.

Stage 6

Paused or Deleted

People may pause alerts or remove them. Old and unused queries should expire, so the index does not grow forever.

Making Changes Safely

Stored queries are ordinary documents, so editing one means replacing it with a new version. There is a brief moment during which the old version is still visible, until the change is refreshed and searchable. Elasticsearch makes new documents visible on a short schedule, usually about a second. For alerts, this delay is fine. But be aware that a query saved just now may not match a document percolated in the same instant.

Everyday Analogy

Think of a notice board at a community center. When someone pins a new note, it takes a moment for the clerk to update the master list that everyone consults. During that short moment, the clerk still works from the old list. A note that was pinned only a second ago may be missed by a letter that arrives right now.

Expiry and Cleanup

Saved searches that nobody uses waste space and processing time. Give each stored query a creation date and a last-used date, and remove those that have been quiet for a long time, after warning the owner. Some systems also let users set an end date, such as “alert me until I move house.” A good cleanup habit keeps the percolator index small and matching fast.

19A Worked Example, Start to Finish

A short story with numbers makes the ideas concrete. Here is an invented example of a job board and its job alerts.

The Setting

A job board has two million saved searches from candidates. About six thousand new jobs are posted each hour, which is under two per second. The team wants alerts sent within a few seconds of a job being posted. All figures in this example are invented to illustrate the reasoning and are not from a real company.

The Design

QuestionDecisionReason
Where do saved searches live?A separate percolator index with fields for owner, country, status and the stored querySeparate scaling and tuning from the ordinary job index
How do we narrow the pool?Filter by the job’s country and by active status before matchingCuts two million queries to a few hundred thousand
How do we percolate?Small batches of a few jobs, collected for up to one secondShares overhead while keeping alerts near real time
What do we return?Only the owner identifier and alert preferences, plus highlightsSmall responses and clearer alerts
How do we notify?Matches go to a queue, and workers send emails or push messagesSlow email services cannot slow down matching

What Happens to One Job

A company posts a job called “Senior Data Engineer, Remote, Python and Spark” in the United Kingdom. The ingestion service stores it in the job index and sends it to the matching service. The percolate request filters to active saved searches for the United Kingdom, about 240,000 of them. Candidate selection looks at the words in the job and shortlists about 300 stored queries that share key terms. Verification confirms that 42 of them truly match, including candidates who asked for “data engineer” and “python”, and one who asked for “spark remote”. The response carries the 42 owner identifiers and highlights of the matching words.

The matching service removes six candidates who already received an alert for a near-identical job an hour earlier, then queues 36 alerts. Workers send the emails, each one showing the highlighted words that matched. Total time from posting to queue is under a hundred milliseconds, and emails leave within a few seconds.

What Went Well, and What Was Tuned

In the first test, without the country filter, the same request took several times longer, because more than a million stored queries were checked in candidate selection. Adding the filter fixed most of the delay. A second problem was a small number of very vague saved searches such as “any job”, which were candidates for every posting and produced huge, unwanted alert volumes. The team added a rule requiring at least two conditions in every saved search, and the noise stopped.

i
Lesson From the Example

Two simple habits did most of the work: filtering stored queries by a metadata field, and requiring saved searches to be specific. The percolator itself did what it always does. The design around it decided whether the system was fast and pleasant or slow and noisy.

20Designing the Percolator Index

Good index design makes everything else easier. This chapter covers the main decisions.

One Index or Many

You can keep all stored queries in one index or split them into several. A single index is simplest, and works well when all queries use the same mapping and similar traffic. Separate indices help when different kinds of queries have different mappings, when tenants need strong isolation, or when different parts of the business have different performance needs. Adding an alias that points to several indices lets one percolate request cover them all when needed.

Choosing the Number of Shards

Shards spread stored queries over the cluster. Too few shards means each does too much work and only a few nodes are used. Too many shards means each does little and the fixed setup cost of every request grows. A useful method is to estimate the number of stored queries and the time to match a typical document, then test with two or three shard counts, and pick the smallest one that meets your latency target with room to spare.

Routing by Tenant or Region

Routing lets you decide which shard stores each query, using a value such as a customer identifier or region. When you percolate with the same routing value, Elasticsearch asks only the shards that hold that value, not all of them. For systems where every request concerns one tenant or one region, routing cuts the work sharply, and it also improves isolation between tenants.

Everyday Analogy

A large hotel keeps guest-list cards in separate drawers for each wing. When a visitor asks for someone in the east wing, the receptionist opens only the east-wing drawer, not the whole cabinet. Routing works the same way. The drawer is chosen by a value that every card carries, and most requests know which drawer they need.

Choice 1

Separate From Documents

Keep stored queries apart from ordinary documents, so each can be scaled, backed up and rebuilt on its own.

Choice 2

Include Filter Fields

Add fields for the things you filter by, such as country, tenant, language and status, so filtering is cheap.

Choice 3

Use Routing Where It Fits

Route by tenant or region when most requests concern only one, to reduce the shards asked.

Choice 4

Plan for Rebuilds

Keep the original queries in your own database, and use an alias so you can switch to a rebuilt index without downtime.

*
Practical Tip

Use an alias in your application code instead of a fixed index name. When you need to rebuild the percolator index for a new analyzer or a bigger shard count, you can build the new index in the background and switch the alias in one step.

21Security

The percolator often stores queries written by outsiders, such as users of your website. Treat those queries with care.

User-Written Queries Are Untrusted Input

If people can save their own searches, they can accidentally, or deliberately, write queries that are very expensive. A query with a wildcard on a very common prefix, a huge list of terms, or a complicated regular expression may take a long time to verify, and it would run for every document in which it is a candidate. One bad query can slow down everyone’s alerts.

The defense is to never store raw queries from users. Instead, let users fill in a structured form, such as keywords, price range and location. Your service builds the actual query from those fields, using only safe query types and limits you have chosen. This is the same rule that protects databases from injection: build queries from validated parts, not from raw user text.

Everyday Analogy

A restaurant lets guests choose dishes from a menu. It does not let guests walk into the kitchen and write their own cooking instructions on the wall. The menu is the structured form, and the kitchen instructions are the stored query. The restaurant stays in control of what actually gets cooked.

Limits Per User

  • Number of saved searches. Cap how many each user can have, so one account cannot flood the index.
  • Size and shape. Limit the number of conditions and the number of terms in each query.
  • Allowed query types. Permit only the types you have tested and know to be cheap.
  • Creation rate. Limit how often a user or an automated script can create or change saved searches.

Keep Tenants Apart

In a system with many customers, one customer’s stored queries and alerts must never leak to another. Store a tenant identifier in every stored query, and always apply a filter on it in every percolate request. Consider using Elasticsearch’s security features, such as roles that limit which documents a user or service can see, so the rule is enforced by the cluster and not only by your code.

Protect the Content

Incoming documents may contain private data, such as messages or personal details. Percolate requests carry the whole document, so encrypt connections with TLS, restrict who can call the matching service, and avoid logging full documents in application logs. Alerts sent to users should show only the parts of a document that they are allowed to see.

!
Watch Out

A stored query can reveal something about its owner, such as their job search or their interests. Treat the percolator index as personal data, apply the same access controls and retention rules as you would for any user profile, and delete queries when accounts are closed.

22High Availability, Failure Scenarios and Recovery

A missed alert is a silent failure, which makes reliability especially important for percolator systems.

Reliability Basics

The percolator index is an ordinary Elasticsearch index, so it gets the usual protections: replica shards on other nodes, spread across zones, so a node failure does not lose stored queries or stop matching. Keep at least one replica of the percolator index. Since your application also holds the original queries in its own database, the percolator index can always be rebuilt from that source.

ScenarioWhat You SeeLikely CauseWhat To Do
Matching service downDocuments arrive, but no alerts are queuedService crash or deployment faultRestart it, and replay documents from the ingestion queue for the missed period
Percolate requests time outSlow or failing matchingHeavy queries, big batches or overloaded nodesAdd filters, reduce batch size, find the expensive queries and add capacity
Alerts stop for some wordsUsers report missing alertsAnalyzer change or mapping mismatchRun the known-match test suite and rebuild the index if needed
Node lostBrief errors, then recoveryHardware or network failureReplicas take over, check that cluster health returns to green
Alert floodHuge number of matches for one documentVague saved searches or a very popular itemCap matches per document, page through results and rate-limit sends
Duplicate alertsSame user gets repeated alertsRetries, edits or replaysRecord which alerts were sent and make sending idempotent

Never Lose a Document

The percolator only matches the documents you give it. If your matching service is down, documents that arrive in that time are not matched, unless you have a way to catch up. The safe design puts new documents onto a durable queue first, and lets the matching service consume from it. If the service stops, documents wait in the queue and are matched when it returns. Alerts are late, but none is lost.

Everyday Analogy

A mailroom clerk who goes on a break leaves a tray for arriving letters. When the clerk returns, the letters in the tray are sorted, and nobody’s mail is lost. Without a tray, letters arriving during the break would slide off the desk. The durable queue is the tray.

*
Practical Tip

Record the last document successfully matched. After an outage, you know exactly where to resume. You can even percolate stored documents from the ordinary index for the missed time range, since the percolate query can read documents that are already stored.

23Monitoring, Logging and Metrics

Because failures are quiet, monitoring must actively look for the absence of alerts as well as errors.

The Numbers That Matter

Speed

Percolate Latency

Time per request, tracked at the average and at the slowest one or five percent. Slow tails hide trouble that averages miss.

Volume

Documents Per Second

How many documents are percolated, and how many are waiting in the queue. Growing queues warn of overload.

Result

Matches Per Document

The average and maximum number of matches. Sudden jumps suggest vague queries or a popular item. Sudden drops suggest a break.

Size

Number of Stored Queries

Total and per tenant or region. Growth here drives cost and latency, and unusual growth can mean abuse.

Health

Errors and Timeouts

Failed or rejected percolate requests, and the reasons, such as memory pressure or overloaded thread pools.

Delivery

Time From Document to Alert

The end-to-end delay a user experiences, from posting to notification, which is the number that really matters.

Watching for Silence

A percolator system can fail by simply matching nothing. Set an alert if the number of matches per hour drops far below the normal level for that time of day. Also keep a small “canary” query and a canary document that must always match. Percolate the canary every few minutes. If it stops matching, you know that something in the chain has broken, even if there are no error messages.

Finding Expensive Queries

Elasticsearch offers slow logs, which record requests that take longer than a limit you set. Use them on the percolator index to find slow percolate requests. If a few stored queries are the cause, you can identify them by looking at which queries are candidates most often and are slow to verify, then work with their owners to make them more specific.

!
Watch Out

Do not rely only on error counts. A system with zero errors and zero alerts is not healthy. Always monitor the positive signal, the number of matches and alerts delivered, along with the negative ones.

24Advantages, Disadvantages and Trade-offs

The percolator is a strong tool for a specific job. A fair look at its strengths and limits helps you decide when to use it.

Advantages

  • Solves the “which rules match this document?” problem directly, without running every rule
  • Reuses the full Elasticsearch query language and text analysis
  • Scales to very large numbers of stored queries with candidate selection and filters
  • Rules are data, so they can be added or changed instantly without a software release
  • Supports batching, highlighting and combination with ordinary filters
  • Ships as part of Elasticsearch, so there is no separate matching engine to run
  • Transparent and explainable, since each match comes from a readable query

Disadvantages

  • Does not notify anyone by itself, so you must build the calling and delivery parts
  • Judges one batch of documents at a time and has no memory of earlier documents
  • Some query types are not supported, including those that depend on the current time
  • Vague or expensive stored queries can slow every request
  • Changing analysis requires rebuilding the stored queries
  • Fields must be mapped up front, and documents must fit the same shape
  • Adds another index to size, secure and operate

Key Trade-offs to Decide

Freedom versus safety. Letting users write any query gives flexibility but exposes you to costly queries. A structured form limits freedom and protects performance. Most public systems choose the form.

Speed of alerts versus efficiency. Percolating each document immediately gives the fastest alerts, but small requests carry more overhead. Batching for a second or two improves efficiency with almost no visible delay.

One big index versus several. One index is simple to run. Several indices give isolation and independent tuning at the cost of more to manage.

Rules versus learning. Stored rules are clear and controllable but need human upkeep. Machine learning handles fuzzy cases but is harder to explain. Many systems use both.

25Design Patterns and Anti-Patterns

Teams that have run percolators in production repeat the same good habits, and the same avoidable mistakes.

Patterns That Work

Pattern 1

Filter, Then Percolate

Always narrow stored queries with cheap metadata filters, such as region or tenant, before the matching begins.

Pattern 2

Queue Between Match and Send

Place matches on a durable queue so that slow notification providers never block the matching step.

Pattern 3

Structured Saved Searches

Let users fill in a form, and build the stored query in your own code with safe query types and limits.

Pattern 4

Source of Truth Elsewhere

Keep the original definition of every saved search in your own database, and treat the percolator index as a rebuildable copy.

Pattern 5

Micro-Batching

Collect documents for a second or so and percolate them together, balancing speed and efficiency.

Pattern 6

Canary Checks

Run a known query and known document through the system regularly, and alert if the match ever fails.

Anti-Patterns to Avoid

ANTI-PATTERN 01Avoid
What people do

They store raw, user-written queries with no checks.

Why it hurts

One expensive or malicious query can slow every percolate request, and users can create huge numbers of them. Costs and delays rise, and other users suffer.

Better approach

Use structured forms, build queries in your own code, limit query types and size, and cap the number of saved searches per user.

ANTI-PATTERN 02Avoid
What people do

They percolate against every stored query with no filters at all.

Why it hurts

Candidate selection has to consider the full set of stored queries, and many irrelevant candidates need verification. Latency grows with the size of the index.

Better approach

Add fields such as country, tenant and status to every stored query, and filter on them in every request.

ANTI-PATTERN 03Avoid
What people do

They expect Elasticsearch to notify users automatically.

Why it hurts

Nothing calls the percolator by itself. The project launches, and no alerts are ever sent because no one wrote the matching and delivery service.

Better approach

Design the whole pipeline: ingestion, percolate call, queue and delivery. Treat the percolator as one component in it.

ANTI-PATTERN 04Avoid
What people do

They put stored queries and real documents in the same index and never separate them.

Why it hurts

The two have different sizes, traffic and mappings. Tuning one harms the other, and rebuilding the percolator side means touching the whole index.

Better approach

Keep a dedicated percolator index, and use aliases so that you can rebuild and switch without downtime.

ANTI-PATTERN 05Avoid
What people do

They try to use the percolator for rules that need history, like “five failures within ten minutes”.

Why it hurts

The percolator sees only the documents in the current request. It cannot count earlier events, so the rule never fires as intended.

Better approach

Use a stream processor or scheduled alerting rules for time-window logic, and use the percolator for per-document rules.

26Best Practices and Common Mistakes

A short list of habits that separate smooth percolator projects from painful ones.

1

Confirm the problem fits

Check that you really have many stored rules and a flow of new documents. If you only have a few conditions over time windows, simpler alerting rules may be enough.

2

Design the document shape first

Agree on the fields, types and analyzers before storing queries. Changing them later means rebuilding the stored queries.

3

Add filter fields to every stored query

Region, tenant, language and status let you skip most stored queries before any matching is done.

4

Validate and limit user input

Use structured forms, allow only safe query types and cap sizes and counts per user.

5

Separate matching from sending

Put matches on a durable queue so failures and slowness in email or push services do not affect matching.

6

Test with realistic volume

Load test with your real mix of queries and documents, including the vague and messy ones, and measure the slow tail.

Common Mistakes

  • Assuming automatic notifications. Forgetting that your own code must call the percolator and deliver the messages.
  • Using time-relative ranges. Trying to store queries with “now” in them and finding that they are refused or behave wrongly.
  • Forgetting to map fields. Storing queries that refer to fields the mapping does not define.
  • Changing analyzers casually. Altering text analysis without rebuilding the stored queries, causing silent missed matches.
  • Ignoring the vague queries. Leaving very broad saved searches in place, which slow every request and flood users with alerts.
  • Too many shards. Splitting a modest percolator index into many shards and paying the setup cost of each request many times over.
  • No source of truth elsewhere. Having no copy of the saved searches outside the percolator index, so a rebuild is impossible.
*
Practical Tip

Write a short “definition of done” for the matching service: a known query and document must match, a known non-matching pair must not, a batch of documents must give the right slots and a filter must exclude the right queries. Run this checklist after every deployment and every mapping change.

27Day-Two Operations: Living With the Percolator

Setting up a percolator is a few days of work. Running it for years is the rest. These are the routine tasks that keep it healthy.

Keeping the Index Tidy

Saved searches accumulate. People change their minds, leave the service or forget they ever created an alert. Regularly remove stored queries for closed accounts, expired alerts and searches that have not produced a match in a very long time. Tell owners before removing anything they might miss. A tidy index is faster and cheaper.

Updating the Mapping

When you want to support a new searchable field, add it to the mapping first. New fields can usually be added without a rebuild. But changing the type or analyzer of an existing field cannot be done in place. For those changes, create a new percolator index with the new mapping, copy the stored queries into it from your own source of truth, test it side by side and then switch the alias. Keep the old index for a short while as a rollback.

Upgrading Elasticsearch

Read the release notes for the versions you are upgrading through. The percolator has changed across versions, and older systems used a different, separate percolate interface, which has long since been replaced by the current query. Test your stored queries and your known-match checklist on the new version before upgrading production, and watch for any query types that are no longer accepted.

Everyday Analogy

A community notice board needs regular care. Old notes must be taken down, new categories need new sections, and every so often the whole board is replaced with a bigger one. If the board is renovated carelessly, notes fall off and messages are missed. A calm routine of tidying, planning and switching prevents that.

Reviewing the Heaviest Queries

Every month or so, look at which stored queries are slow or are candidates for a very large share of documents. Talk to their owners, or improve the form that created them, so that they are more specific. A short review often shows one or two patterns that account for most of the load, and fixing them can free up a great deal of capacity.

*
Practical Tip

Put recurring chores on a calendar: tidy expired queries, review the heaviest queries, run the known-match checklist and rehearse a rebuild from the source of truth. Tasks that are scheduled tend to get done, while tasks kept in memory tend to wait for the next incident.

28A Simple Troubleshooting Guide

When the percolator seems to misbehave, an ordered set of checks finds the cause faster than guessing.

1

Is the query stored?

Fetch the stored query by its identifier and confirm that it exists, is active and has the fields you expect, including region and status.

2

Does the query match the document in plain search?

Index the sample document in a scratch index with the same mapping, and run the stored query against it as an ordinary search. If it does not match there, the query itself is the problem.

3

Do the filters exclude it?

Check that your metadata filters, such as region and status, are not removing the stored query before matching. This is a very common cause of a missing alert.

4

Do the fields line up?

Compare the fields in the document with the fields in the mapping. A misspelled field or a value of the wrong type can prevent a match without any error.

5

Is analysis consistent?

Check whether the analyzer changed since the query was stored. If so, store the query again and test once more.

6

Is the pipeline delivering?

If matches are found but no alert arrives, look at the queue, the workers and the notification provider. The percolator may be working perfectly while the delivery side is stuck.

Common Symptoms and First Guesses

SymptomFirst Thing To Check
A saved search never matches anythingWhether it is too specific, whether its fields are mapped and whether filters exclude it
Storing a query fails with an errorWhether all fields exist in the mapping and whether the query type is supported
Alerts arrive for some users but not othersPer-user filters, status fields and analysis differences
Percolate requests are slowMissing filters, vague queries as candidates, batch size and shard count
Huge number of matches for one documentVery broad stored queries, or a popular item that matches many specific ones
Matches stopped after a mapping changeAnalyzer or field type change, so stored queries need to be stored again
i
A Good Habit

Keep a small library of “must match” and “must not match” pairs for real examples that once went wrong. Every bug you fix becomes a permanent test, and after a year, this library is the best protection you have against regressions.

29Real-World Scenarios

The stories below are illustrative composites showing how different kinds of organizations use the percolator. They are not accounts of specific companies.

A Property Portal With Saved Searches

A property site lets people save searches by area, price and number of bedrooms. Every new listing is percolated against active saved searches for its region. Matching users get a message with the listing’s photo and the words that matched. Because filters cut the pool to one region, matching stays fast even on busy mornings.

A News Organization Tagging Stories

A newsroom keeps a library of topic rules written by editors: sports, politics, science and hundreds of narrower topics. Each incoming story is percolated, and matching topics become tags that decide which pages and newsletters carry the story. When a new topic emerges, an editor adds one rule and the next story is tagged immediately.

A Support Team Routing Tickets

A software company receives thousands of support requests. Each team maintains rules about the products, error messages and customer tiers it handles. Incoming tickets are percolated, and the matching rules decide which team receives each ticket. When the company launches a new product, the support lead writes rules for it in minutes.

A Regulated Firm Screening Messages

A financial firm must screen internal messages for restricted terms and phrases. The compliance team maintains the rules as stored queries. Every message is percolated, and matching messages are flagged with highlights for human review. When regulations change, updated rules are stored the same day, without a software release.

A Marketplace Watching for Prices

A marketplace lets buyers set alerts such as “vintage camera, under a certain price, within fifty kilometers.” Each new listing is percolated against alerts in its region, and buyers are notified the moment a matching item appears. The system limits each buyer to a set number of alerts so that the index stays healthy.

30Common Myths and Misunderstandings

Half-true ideas about the percolator cause wasted effort and bad surprises. Here are the ones that appear most often.

Myth 1

“The percolator sends notifications.”

It only tells you which stored queries match. Your own code must call it and deliver the messages.

Myth 2

“It watches my index automatically.”

It does not monitor anything. It answers a request that you send for each document or batch.

Myth 3

“It runs every stored query against every document.”

Candidate selection rules out most stored queries first, so only a small shortlist is really run.

Myth 4

“Any query can be stored.”

Queries that join to other documents, need outside lookups or depend on the current time are not supported.

Myth 5

“It is a machine-learning feature.”

It is exact rule matching. Every match comes from a readable stored query.

Myth 6

“It can detect patterns over time.”

It judges each document, or batch, on its own. It has no memory of earlier documents.

Myth 7

“The score tells me how good the match is.”

The hit score is not a measure of document quality. Most systems treat the result as a plain list of matches.

Myth 8

“Set it up once and forget it.”

Saved searches pile up, mappings evolve and abusive queries appear. Regular tidying and monitoring keep it healthy.

i
A Healthy Attitude

Think of the percolator as a very fast, very literal clerk. It follows the rules you give it exactly and tells you which ones a document satisfies. It does not guess, remember or deliver messages, and it works best inside a well-designed pipeline.

i
Licensing Note

The percolator ships as a built-in part of Elasticsearch, but licensing terms and feature availability differ between versions and distributions. Confirm the details for your version in Elastic’s current documentation before you commit to a design.

31Glossary of Terms

A quick reference for the important words in this guide, in plain language.

TermPlain Meaning
AliasA movable name that points to one or more indices, so you can switch indices without changing application code
AnalyzerThe recipe that breaks text into searchable terms
BatchingSending several documents in one request to share overhead
CandidateA stored query shortlisted because its key terms appear in the incoming document
Candidate selectionThe fast first step that shortlists stored queries that could match
DocumentOne item stored in Elasticsearch, such as a listing or an article
HighlightingMarking the words in a document that caused a match
IndexA container for documents, or for stored queries, in Elasticsearch
LatencyHow long one request takes
MappingThe description of an index’s fields and their types
Metadata filterAn ordinary filter on fields stored beside a query, such as region or status
Percolate queryThe query that takes documents and returns matching stored queries
PercolatorThe Elasticsearch feature for storing queries and matching documents against them
Percolator fieldThe special field type that holds a stored query
PollingRunning a search repeatedly on a schedule to check for changes
Query extractionSaving key terms from a query at storage time to speed up candidate selection
ReplicaAn extra copy of a shard that protects data and adds capacity
Reverse searchFinding which stored queries match a given document
RoutingChoosing which shard stores or serves a record using a value such as tenant or region
ShardOne piece of an index, stored and searched independently
SlotThe position number that says which of several percolated documents matched
Stored queryA query saved in an index so it can be matched against future documents
ThroughputHow many documents or requests can be handled per second
VerificationRunning each shortlisted query for real against the document to confirm the match

32Frequently Asked Questions

Quick answers to the questions people ask most often when they first meet the percolator.

Q1What is the percolator in one sentence?
It is an Elasticsearch feature that lets you store queries in an index and then find out which of those stored queries match a given document, which is the reverse of normal search.
Q2Does it send alerts by itself?
No. It only returns the list of matching stored queries. Your own application must call it for each new document and send the notifications.
Q3How does it stay fast with millions of stored queries?
It saves key terms from each query when the query is stored. When a document arrives, it quickly shortlists only the queries whose key terms appear in the document, then verifies just those. Filters on extra fields shrink the pool even more.
Q4Can I store any kind of query?
Most query types work, including text, exact values, ranges, locations and combinations. Queries that join to other documents, need lookups elsewhere or depend on the current time are not supported. Check the documentation for your version.
Q5Why can’t I store a query with “now” in a date range?
A stored query is prepared once, when it is saved, so “now” would be frozen at that moment. Handle time rules in your application, for example by adding a field to the document at matching time.
Q6Can I percolate many documents at once?
Yes. You can send a list of documents in one request, and each match tells you which document slots matched. Batching usually improves throughput compared with sending documents one at a time.
Q7Can I percolate a document that is already stored?
Yes. You can point the percolate query at an existing document by index and identifier instead of sending its contents again. This helps when re-checking stored documents against new queries.
Q8Should stored queries live in the same index as my documents?
It is usually better to keep them in a separate percolator index. The two have different sizes, traffic and tuning needs, and a separate index can be rebuilt on its own.
Q9What happens if I change an analyzer?
Existing stored queries were prepared with the old analyzer, so they may stop matching correctly. You need to store them again, typically by building a new percolator index and switching an alias to it.
Q10Can the percolator detect events over time, like three failures in five minutes?
No. It judges the document or batch in front of it and has no memory of earlier ones. Use a stream processor or scheduled alerting rules for time-window logic.
Q11Is it the same as Kibana alerting or Watcher?
No. Those features usually run a search on a schedule and act on the results, which suits operational conditions. The percolator reacts to each new document and can hold millions of separate rules, which suits user alerts, tagging and routing.
Q12How do I keep one customer’s rules from another’s?
Store a tenant identifier in every stored query and always filter on it in every percolate request. Add security roles and, where suitable, routing by tenant, so isolation is enforced by the cluster as well as your code.
Q13What if users write very expensive queries?
Do not store raw user queries. Let users fill in a structured form, build the query in your code from allowed parts, limit sizes and counts, and monitor slow requests to find offenders.
Q14Is there an older percolator interface I might read about?
Yes. Very old versions of Elasticsearch used a separate percolate interface. Modern versions use a special field type and the percolate query described in this guide, so treat old articles with care and check your version’s documentation.
Q15What is the biggest reason percolator projects go wrong?
Most problems come from the design around it: no metadata filters, vague or unchecked user queries, no delivery pipeline, no monitoring for silent failures and analysis changes without rebuilding. Good design and habits prevent nearly all of them.

33Summary and Key Takeaways

Key Takeaways

  • The percolator is reverse search. You store queries in an index using a special field type, then pass a document in to find out which stored queries match it.
  • It solves the “which rules match this?” problem. It fits alerts on saved searches, tagging and classification by rules, and routing or screening of streams of events.
  • Two-phase matching keeps it fast. Key terms saved at storage time let Elasticsearch shortlist likely queries, and only those are verified against a tiny in-memory copy of the document.
  • Filters and specificity decide performance. Metadata fields such as region or tenant, batching, sensible shard counts and specific queries matter more than any single setting.
  • It does not notify or remember. Your own pipeline must call it for each document and deliver the alerts, and it cannot detect patterns over time or use the current clock inside stored queries.
  • Treat stored queries as untrusted and analysis as fixed. Use structured forms, limit sizes and counts, isolate tenants, and rebuild the index when analyzers change, keeping the source of truth in your own database.
  • Watch for silence. Monitor matches and delivered alerts as well as errors, use canary queries, and keep a queue between matching and sending so no document is lost.