What Is a Dense Vector Field in Elasticsearch?

What Is a Dense Vector Field in Elasticsearch?

A complete, plain-English guide to the field type that lets Elasticsearch search by meaning: what a vector is, where it comes from, how similarity is measured, how nearest neighbors are found among millions of vectors, and what it costs in memory, speed, and care.

Imagine a huge map, not of countries, but of ideas. Every sentence, product, or picture has a spot on it. The sentence “a small furry pet that purrs” sits very close to “kitten” and “cat,” a little farther from “dog,” and very far from “tax return.” Nobody drew this map by hand. A computer program learned it by reading enormous amounts of text, and it places things near each other when they mean similar things, even when they share no words at all.

Now suppose that a user searches for “feline companion.” Ordinary keyword search looks for those exact words and finds nothing about kittens. But if every document has coordinates on the map of meaning, the search can simply ask: which documents are closest to the coordinates of “feline companion”? Kittens and cats come back. The list of coordinates stored with each document is called a vector, and the field type that holds it in Elasticsearch is the dense vector field. This guide starts from zero, opens the machinery step by step, and ends with the numbers, the trade-offs, and the habits that keep vector search accurate, fast, and affordable in production.

1What a Dense Vector Field Actually Is

Three plain ideas, put together: a list of numbers, a fixed length, and closeness. Once each is clear, the rest follows naturally.

A vector is simply an ordered list of numbers, such as 0.12, negative 0.83, 0.05, and so on. Each number says how far along one direction a thing lies. With two numbers you can place a point on a flat sheet of paper. With three, you can place it in a room. Vectors used in search have many more numbers, commonly a few hundred or a thousand, so they place things in a space with that many directions. We cannot picture such a space, but the arithmetic works exactly as it does on paper.

A dense vector is one in which almost every position holds a meaningful number. This is different from a sparse vector, where most positions are zero and only a few carry values. Dense vectors are typically produced by machine-learning models called embedding models, which read a piece of content and return a list of numbers that captures its meaning. The list is called an embedding. Content with similar meaning receives embeddings that lie close together.

The dense vector field is the Elasticsearch field type that stores one such vector per document. You declare it in the mapping, telling Elasticsearch how many numbers each vector has, and what kind of closeness to use. Then you fill it with the embeddings of your content, and search it with a technique called k-nearest-neighbor search, or kNN: given a query vector, find the k stored vectors that lie closest to it.

Everyday Analogy

Think of a taste profile. A restaurant rates every dish on twenty scales: sweetness, saltiness, spiciness, crunchiness, and so on. Each dish becomes a list of twenty numbers. To find dishes similar to one you love, you do not read menus. You look for dishes whose twenty numbers are closest to the ones of your favorite. A dense vector is such a profile, only produced by a model, with hundreds of scales that nobody named.

One vector
per document, per dense vector field
Fixed length
every vector in the field has the same number of dimensions
Closest wins
results are the stored vectors nearest to the query vector
A dense vector does not hold your words. It holds a position on a map of meaning.

What it is not

A dense vector field is not a text field. It does not split words, it has no postings lists of terms, and it cannot be searched with ordinary word queries. It is also not the place where the model lives. The embedding model is a separate program, inside or outside Elasticsearch, that produces the numbers. The field just stores them, indexes them for fast nearest-neighbor lookup, and compares them at search time. Finally, it is not a replacement for keyword search. It answers a different question, “what is similar in meaning?”, and works best together with the keyword tools, as Chapter 9 shows.

i
Do Not Mix Up the Names

Elasticsearch has several vector-related things. The dense vector field stores numbers and supports similarity search. The sparse vector field stores a small number of weighted terms and is used by different models. The semantic text field is a convenience that can create and store embeddings for you. This guide is about the dense vector field, and mentions the others only to explain how they relate.

The one-sentence version

If you remember one line from this chapter, make it this: a dense vector field stores, for each document, a fixed-length list of numbers produced by an embedding model, and lets Elasticsearch find the documents whose lists lie closest to a query list, which means finding the documents most similar in meaning.

2Why It Exists: Words Are Not Meaning

Every feature is born from a frustration. The frustration here is that people mean one thing and write many.

Keyword search matches the words you type against the words stored in documents. It is fast, precise, and predictable. But human language is slippery. The same idea is expressed in many ways: “cheap flights,” “budget airfare,” “low-cost tickets.” A search for the first may miss documents that use only the second. The same word can mean different things: “bank” of a river and “bank” for money. And people often do not know the exact words: a shopper types “shoes for running in the rain” while the catalog says “waterproof trail sneakers.”

Search engineers have fought this for decades with synonym lists, stemming, spelling correction, and hand-tuned rules. These help, but they are labor-intensive, brittle, and always incomplete. Embedding models offer a different approach. Instead of listing which words are equivalent, they learn from vast amounts of text what tends to appear in similar contexts, and turn that knowledge into positions on a map. Content about the same thing ends up in the same neighborhood, whichever words it uses, and often whichever language it is written in.

Everyday Analogy

A librarian who matches only exact titles will fail a visitor who asks for “that book about the boy wizard.” A librarian who understands what the visitor means will walk straight to the right shelf. Vector search gives the search engine that second kind of understanding.

A short history

1

Word-based search only

Elasticsearch began as a keyword search engine built on inverted indexes. Meaning was approximated with analyzers and synonyms.

2

Vectors as stored numbers

Around version 7, a field type for vectors appeared, and similarity could be computed inside scoring scripts. This worked by comparing the query with every candidate document, which is exact but slow on large collections.

3

Indexed nearest-neighbor search

Around version 8, vectors could be indexed in a graph structure, and approximate nearest-neighbor search became a first-class feature, fast enough for millions of vectors.

4

Compression and convenience

Later releases added compact number types, quantization to shrink memory, hybrid search with keywords, filters during graph search, integration with embedding models, and fields that manage embeddings automatically.

5

Today: a general-purpose retrieval layer

Dense vector fields serve semantic search, recommendations, and the retrieval step of applications that use large language models.

The exact release for each step is worth double-checking in the release notes of your version. The direction of travel is what matters: from “compare everything” to “search a graph,” and from “raw numbers” to “compressed, managed, and combined with keywords.”

Why not just use synonyms?

Synonyms are still useful, and often the best answer for a known, small vocabulary, such as product codes and brand names. But a synonym list cannot cover every way that people phrase a question, it needs constant upkeep, and it cannot handle whole sentences. Vectors handle the long tail of phrasing automatically. The price is that they are approximate, they cost memory, and they depend on the quality of the model that produced them.

QuestionKeyword searchVector search
Finds exact words and codesExcellentWeak, may blur exact tokens
Finds paraphrases and related ideasWeak without synonym listsStrong
Handles long, natural questionsModerateStrong
Works across languagesNo, unless translatedYes, with a multilingual model
Explains why a document matchedYes, shared wordsHard, only a closeness score
Cost in memory and computeLowMuch higher

3Core Concepts You Need First

A dozen words explain nearly everything about vector search. Learn them here, and later chapters will read like common sense.

Numbers

Vector

An ordered list of numbers. In search, it stands for the position of one piece of content on a map of meaning.

Numbers

Dimension

One position in the list. A vector with 768 numbers has 768 dimensions. All vectors in a field share the same count.

Making

Embedding

The vector that a model produces for a piece of content. “Embed” means to turn content into such a vector.

Making

Embedding model

The machine-learning program that reads content and returns its embedding. Different models give different vectors.

Closeness

Similarity and distance

Ways to measure how near two vectors are. High similarity or low distance means the contents are alike.

Closeness

Normalization

Scaling a vector so that its length is exactly one. It makes some similarity measures faster and simpler.

Search

Nearest neighbor and k

The stored vectors closest to the query. The number k says how many you want back.

Search

Exact and approximate

Exact search compares against every vector. Approximate search uses a shortcut structure and may miss a few true neighbors.

Structure

HNSW graph

The layered network of vectors, linking each one to close neighbors, that makes approximate search fast.

Quality

Recall

The share of the true nearest neighbors that a search actually returns. Ninety percent recall means nine of the ten true closest.

Size

Quantization

Storing each number with fewer bits, to shrink memory and speed up comparison, at some cost in accuracy.

Storage

Segment

A sealed set of files inside a shard. Each segment keeps its own vectors and its own graph.

Where the numbers come from

An embedding model is trained on a huge collection of examples until it learns to place similar things near each other. After training, you give it a sentence, an image, or another kind of content, and it returns a vector of fixed length. The same model always returns vectors of the same length, and only vectors from the same model can be compared. A vector produced by one model means nothing on the map of another, just as coordinates from one atlas are meaningless on a different planet’s map.

Everyday Analogy

Two friends draw maps of the same town, but one measures distances in miles from the church and the other in kilometers from the station. Coordinates from the first map cannot be looked up on the second. In the same way, vectors from different embedding models cannot be mixed in one field.

Distance and similarity are two sides of one coin

When two vectors are close, their distance is small and their similarity is large. Elasticsearch turns each measure into a score, so that a bigger score always means a better match. You choose the measure in the mapping. The three classic ones are the straight-line distance, the angle between the vectors, and the dot product. Chapter 6 explains them.

Why “approximate” is acceptable

Finding the exact nearest neighbors among millions of vectors means comparing the query with every one of them. With 768 numbers each, that is billions of multiplications per query. Approximate methods build a network of links between close vectors and follow it from a starting point toward the query, checking only a tiny fraction of all vectors. They may occasionally miss the true closest one, but they answer in milliseconds. For search applications, where the “best” result is a matter of degree anyway, this trade is almost always worth it.

!
Common Trap

A high similarity score does not prove that a result is correct or useful. It says only that the model considers the two pieces of content close. The scores depend on the model and the metric, and they are not comparable across different models or fields.

Quick glossary

WordPlain meaning
kNNk-nearest-neighbor search: return the k stored vectors closest to a query vector.
ANNApproximate nearest neighbor: a faster search that may miss a few true neighbors.
CandidateA vector examined during search and kept for possible return.
Hybrid searchCombining keyword search and vector search in one request.
ChunkingCutting long text into shorter pieces so that each gets its own embedding.
Sparse vectorA vector where almost all positions are zero, used by different kinds of models.
Page cacheThe operating system’s memory for recently used file data, where vectors should stay.
HeapThe working memory of the Java program that Elasticsearch runs in.

4Architecture and Components

Where do vectors come from, where do they live, and which parts work together when a user searches?

Vector search has two halves that mirror each other. On the indexing side, content is turned into vectors and stored. On the search side, the user’s query is turned into a vector with the same model, and Elasticsearch looks for stored vectors near it. The embedding model sits outside the field, and the field itself is the storage and the index.

flowchart TB
    T["Text, image, or other content"] --> EM["Embedding model: turns content into a list of numbers"]
    EM --> V["Vector with a fixed number of dimensions"]
    V --> F["dense vector field in the document"]
    F --> S["Segment: raw vectors plus an HNSW graph"]
    Q["User query"] --> QE["Same embedding model makes a query vector"]
    QE --> K["kNN search: find the nearest vectors"]
    S --> K
    K --> R["Top results with scores"]
    
Figure 1: Content becomes a vector at indexing time, the query becomes a vector at search time, and kNN search finds the nearest stored vectors.

Read the picture from top to bottom. Content passes through an embedding model, producing a vector of fixed length. The vector is stored in the document’s dense vector field. When the document is written into a segment, the vectors are saved in a file and, if the field is indexed, linked into a graph. At search time, the query text goes through the same model, giving a query vector. The kNN search walks the graph of each segment, collects the nearest candidates, and returns the best results with their scores.

The main components

Producer

Embedding model

Runs inside Elasticsearch, on machine-learning nodes, or in an outside service. It returns the vector for a piece of content.

Glue

Inference service and pipelines

Connects models to indexing and search, so that documents are embedded on the way in, and queries on the way out.

Storage

Dense vector field

Holds one vector per document, with its dimension count, element type, similarity, and index options.

Storage

Vector files

Per segment, a file with the raw vectors, stored in order, ready to be read from the file cache.

Index

HNSW graph

Per segment, a layered network linking each vector to its close neighbors, used to find candidates quickly.

Search

kNN query

Takes a query vector, the number of results, the number of candidates, and optional filters.

Combine

Hybrid ranking

Merges vector results with keyword results into one ranking.

Memory

Operating system file cache

Keeps vectors and graphs in memory, outside the Java heap, so that searches read them fast.

Vectors live per segment

Like other indexed data, dense vectors are stored inside segments. Each segment has its own vector file and its own graph, covering only the documents of that segment. A shard is made of several segments, so a kNN search on a shard runs once per segment and combines the findings. When segments merge, the vectors are copied into a new segment and the graph is rebuilt or extended. This makes the number of segments, and the cost of merges, important themes of the chapters that follow.

Everyday Analogy

Imagine a city divided into districts, each with its own street map and its own list of the nearest cafes. To find the ten cafes nearest to you in the whole city, you ask each district for its best candidates and then pick the overall best. If the city were one big district, you would ask only once, but the map would be huge.

Walking one search through the machine

1

The user types a question

For example, “waterproof shoes for trail running.”

2

The question becomes a vector

The same embedding model that produced the stored vectors converts the question into a query vector.

3

The request reaches the shards

The coordinating node sends the query vector to a copy of each shard.

4

Each segment is searched through its graph

The search starts at an entry point and hops toward the query, collecting close candidates. Filters restrict which documents count.

5

Each shard returns its best candidates

The nearest vectors found across its segments, with scores.

6

The coordinating node picks the winners

It merges the shard results and returns the best k to the user.

i
Why This Matters for Tuning

Because the graph, the vectors, and the file cache all take memory, and because every segment adds a search, the amount of RAM, the number of segments, and the number of shards decide how fast and how cheap vector search will be. The following chapters return to these points.

5Anatomy of the Dense Vector Field

Now we open the mapping and look at each option. A small number of choices control almost everything.

When you declare a dense vector field, you tell Elasticsearch a handful of things. The most important are the number of dimensions, the type of each number, whether the field should be indexed for fast search, which similarity to use, and how the index should be built. The table below lists them in plain words.

OptionWhat it meansTypical choice
DimensionsHow many numbers each vector holds. Must match your model exactly.The size your embedding model produces, often several hundred to about a thousand
Element typeHow each number is stored: as a decimal number, as a small whole number, or as a single bit.Decimal numbers by default, smaller types for compact models
IndexedWhether a graph is built so that nearest-neighbor search is fast.On, for anything searched by similarity at scale
SimilarityHow closeness is measured: distance, angle, dot product, or maximum inner product.The one recommended for your model, often cosine or dot product
Index optionsHow the graph is built and whether numbers are compressed.The default graph, often with compression in recent versions
Everyday Analogy

Setting up a photo album, you decide the page size (dimensions), whether photos are kept in color or black and white (element type), whether to keep a quick-reference index at the back (indexed), and how to judge whether two photos look alike (similarity). The choices are made once, before the photos go in.

Dimensions must match the model

The number of dimensions is fixed for the field, and every vector stored in it must have exactly that many numbers. If your model produces vectors of 768 numbers, the field must say 768. A vector with a different length is rejected at indexing time. The maximum allowed number has grown across versions, and now reaches several thousand, but higher numbers mean more memory and slower comparison, so more is not better by itself. Choose a model whose size fits your budget.

Element types

Default

Float

Each number is a four-byte decimal. Most embedding models produce these, and this type keeps full precision.

Compact

Byte

Each number is a single byte, a whole number in a small range. It needs a model that outputs such values, or a compression step, and quarters the size.

Tiny

Bit

Each number is a single bit, used with models or methods that produce binary vectors. It shrinks size dramatically, and is compared by counting differing bits.

One vector per field

In the standard arrangement, a dense vector field holds one vector per document. It cannot hold a list of vectors for the same document. If a long document needs several vectors, for example one per paragraph, the usual answers are to cut the document into chunks and index each chunk as its own document, or to place the chunks in nested objects, each with its own vector. Both designs are discussed in Chapter 11.

The vector and the original source

By default, the document’s original source contains the vector as an array of numbers, and the same numbers are also stored in the special vector files. This means the numbers are kept twice, once in the source and once in the vector storage, and every time the source is fetched or a document is updated or reindexed, hundreds of numbers travel with it. Newer versions let you keep vectors out of the returned source, or handle them more economically, to save space and bandwidth. Check the behavior of your version, because the defaults have changed over time.

1

Choose the model first

Its output size and recommended similarity decide the mapping.

2

Declare the field

Set dimensions, element type, and similarity to match the model.

3

Decide on indexing and compression

Turn on the graph, and pick a compression level appropriate to your size and accuracy needs.

4

Decide what happens to the source

Keep vectors in it or leave them out, according to your version and needs.

5

Test on a sample

Index a realistic sample, measure size, speed, and result quality, and adjust before the full load.

Changing the mapping later

Most of these choices are permanent for an index. You cannot change the number of dimensions, or the similarity, of an existing field. Some newer versions allow certain upgrades of the compression setting, but in general, changing the design of a dense vector field means creating a new index with a new mapping and reindexing the data. If you also change the embedding model, all vectors must be recomputed, because the old ones are meaningless to the new model. Plan for this from the start, for example by giving indexes names that include the model version, and by using aliases to switch between them.

!
A Note on Details

The set of options, their defaults, and their limits differ between versions. This guide describes the ideas, which are stable, and names details only in general terms. Confirm the exact options, defaults, and limits in the documentation of the version you run.

6Measuring Closeness: Similarity Metrics

Nearest neighbor search needs a ruler. The choice of ruler changes which results come first, so it deserves care.

Two vectors are “close” when a chosen measure says so. Elasticsearch offers several measures. Three of them are classic, and one is a specialized variant. Each turns a pair of vectors into a score in which a higher number always means a better match.

flowchart TD
    A["Choose a similarity"] --> B{"Does the embedding model recommend one?"}
    B -- Yes --> C["Use the recommended metric"]
    B -- No --> D{"Are the vectors normalized to length one?"}
    D -- Yes --> E["dot product: fastest, same ranking as cosine"]
    D -- No --> F{"Does vector length carry meaning?"}
    F -- Yes --> G["maximum inner product or straight-line distance"]
    F -- No --> H["cosine: compares direction only"]
    
Figure 2: A simple way to choose a similarity metric.

Straight-line distance

This is the everyday idea of distance: the length of the straight line between two points. It takes into account both the direction and the length of the vectors. Points that lie physically close have a small distance. Elasticsearch converts it to a score so that small distances give large scores. It suits models that were trained with distance in mind, and data where the magnitude of a vector is meaningful.

Cosine similarity

Cosine similarity looks only at the angle between two vectors, ignoring their lengths. Two vectors pointing in the same direction are considered identical in meaning, even if one is much longer than the other. Perfectly aligned vectors score at the top, unrelated ones in the middle, and opposite ones at the bottom. Most text embedding models are designed for cosine similarity, which is why it is the most common choice. A vector with all zeros has no direction, so it cannot be used with cosine similarity, and is rejected.

Everyday Analogy

Two people walking in the same direction are heading to the same place, even if one walks faster and has gone farther. Cosine similarity asks only “are they pointing the same way?” and does not care how far each has gone.

Dot product

The dot product multiplies the numbers of two vectors position by position and adds them up. When both vectors have been scaled to length one, the dot product equals the cosine, and gives the same ranking, but is cheaper to compute. Elasticsearch’s dot product option therefore expects unit-length vectors. Normalizing your vectors once, before indexing, and using the dot product option is a common way to save work on every search.

Maximum inner product

This variant uses the dot product without requiring unit length, so that vector length counts. Some recommendation models use it deliberately: a longer vector might mean a more popular item, and the ranking should reflect that. Because the raw values are unbounded, Elasticsearch scales them into a positive score. Use it only when your model documentation says to.

MetricWhat it comparesVectors must beTypical use
Straight-line distancePosition in space, direction and lengthAny, non-zero not requiredModels trained for distance, image features
CosineDirection onlyNon-zeroMost text embeddings
Dot productAlignment and length, equal to cosine for unit vectorsUnit lengthNormalized embeddings, fastest option
Maximum inner productRaw alignment and lengthAnyRecommenders that encode strength in length

A tiny example

Let us use a two-number picture. Suppose vector A points along the horizontal axis, vector B points straight up, and vector C points diagonally between them. The angle between A and C is 45 degrees, and the angle between A and B is 90 degrees. By cosine similarity, C is closer to A than B is, because the angle is smaller. If you stretch C to twice its length, its direction does not change, so cosine similarity does not change, but the straight-line distance between C and A grows. This shows why the choice of ruler matters: the same three points give different rankings under different measures.

How scores are shaped

The similarity produces a raw value, which Elasticsearch converts into a positive score. For the angle-based measures, the range is mapped so that identical direction gives a score near one, and opposite direction gives a score near zero. For distance, small distances give scores near one, and large distances give scores approaching zero. These scores are for ranking and for combining with other scores. They are not probabilities, and a score of 0.9 does not mean 90 percent chance of being relevant.

Similarity thresholds

A kNN search can also set a minimum similarity, so that results below the threshold are dropped, even if fewer than k results remain. This is useful when you would rather return nothing than return something irrelevant. The threshold is expressed in the units of the raw measure, not the converted score, so read the documentation for your version before choosing a value.

!
Match the Metric to the Model

An embedding model is trained with a specific measure in mind. Using a different one may still work, but can quietly reduce result quality. Read the model’s documentation, choose the recommended metric, and test with real queries before you commit to it.

Normalizing vectors

Normalizing means dividing each number of a vector by its length, so that the new length is exactly one. Many embedding services already return normalized vectors. If yours does not, and you want the fast dot product option, you can normalize in your loading program or in an ingest step. Never normalize some vectors and not others in the same field, and never normalize the stored vectors but forget to normalize the query vector, since mixed lengths would distort the ranking.

7How Vectors Are Stored and Indexed

A vector is only a list of numbers, but storing millions of them so that they can be searched quickly takes careful machinery.

flowchart LR
    A["Document with a vector arrives"] --> B["Vector is added to the in-memory segment and its graph"]
    B --> C["Refresh writes a new segment with vectors and graph"]
    C --> D["Merge combines segments and builds larger graphs"]
    D --> E["Search asks every segment for its nearest candidates"]
    E --> F["Shard combines candidates, coordinator picks the global best"]
    
Figure 3: From an arriving vector to a search across segments.

Two structures per segment

Inside each segment, a dense vector field creates two things. The first is a file of raw vectors, stored one after the other, in the order of the documents. This lets the search read the numbers of any document quickly. The second, if the field is indexed, is the graph: a network in which each vector is linked to a small number of its close neighbors. The graph is what makes approximate search fast. Both are stored in files that the operating system can map into memory.

Everyday Analogy

Think of a very large address book. The vectors file is the book itself, listing every person’s coordinates. The graph is a set of notes saying, for each person, “the five people who live closest to me.” Starting from one person and following the notes, you can walk toward any address without reading the whole book.

Building the graph as documents arrive

When a document with a vector is indexed, the vector is inserted into the graph of the segment that is currently being built in memory. The insertion searches the existing graph for the new vector’s closest neighbors, and links the new vector to them. This is real work, involving many distance calculations, so indexing vectors is much slower than indexing plain text or numbers. The cost grows with the number of dimensions and with the quality settings of the graph.

Refresh and new segments

When a refresh happens, the in-memory graph is written out as a new segment with its own vector file and graph files. Each refresh under heavy indexing creates a new small segment. Small segments have small graphs, which are quick to search but add to the number of graphs that every search must visit.

Merging: the expensive part

In the background, segments are merged into larger ones. For vectors, a merge must produce a graph for the combined segment. Depending on the version, Lucene may reuse the graph of the largest input and insert the vectors of the others into it, or build a new one. Either way, merging vectors involves many distance calculations and uses a lot of processor time, far more than merging text segments of the same size. This is one reason that indexing many vectors continuously can keep a cluster’s processors busy long after the documents have stopped arriving.

1

Vector arrives with its document

The vector must have exactly the declared number of dimensions.

2

It is placed into the in-memory graph

The system searches for its closest neighbors and links to them.

3

A refresh or flush writes the segment

Vectors and graph are saved as sealed files.

4

Background merges combine segments

The graph of the new, larger segment is built, using much processor time.

5

Old segments are removed

Their files are deleted once the merged segment is ready.

How much memory do vectors need?

The single most important sizing fact is that vector search is fast only when vectors and graphs stay in memory, in the operating system’s file cache, not on the Java heap. Reading a vector from disk for every step of a graph walk would be slow. A rough estimate of the memory needed for unquantized decimal vectors is the number of vectors, times four bytes, times the number of dimensions, plus a smaller amount for the graph links, roughly four bytes times the number of links per vector.

A numbers walkthrough

Let us use invented numbers. Suppose you store 10 million vectors of 768 dimensions each as four-byte decimals. The raw vectors take 10 million times 768 times 4 bytes, which is about 30.7 gigabytes. With sixteen links per vector, the graph adds about 10 million times 4 times 16 bytes, which is about 640 megabytes. So around 31 to 32 gigabytes should ideally fit in the file cache across the nodes that hold this data, for good latency. If the same data were stored with each number in one byte, the vectors would take about 7.7 gigabytes. If in a single bit, about 960 megabytes. Compression, which Chapter 10 discusses, is therefore the main way to fit large collections in modest memory.

Storage formApproximate memory for 10 million vectors of 768 dimensionsComment
Four-byte decimalsAbout 31 GB, plus the graphFull precision, largest
One byte per numberAbout 8 GB, plus the graphFour times smaller, small accuracy loss
Half a byte per numberAbout 4 GB, plus the graphEight times smaller, more accuracy loss
One bit per numberAbout 1 GB, plus the graphAround thirty times smaller, needs rescoring for quality

Disk is bigger than memory needs

Even when vectors are compressed for searching, the original decimal vectors are usually kept on disk as well, so that they can be used for rescoring or for rebuilding the compressed copy. This means the disk footprint may be larger than the memory footprint of the searched form. Plan disk and memory separately: memory for what the search touches, disk for everything that must be kept.

Deletes and updates

Deleting a document does not remove its vector from the graph of its segment. The vector stays, marked as deleted, and searches skip it, until a merge rewrites the segment. An update is a delete plus a new document in a new segment. Indexes with constant updates therefore carry dead vectors in their graphs, consuming memory and search effort until merged away.

i
Keep Vectors Out of the Heap

Vectors and graphs are read through the operating system’s file cache, not from the Java heap. Giving the heap too much memory leaves too little for the cache and makes vector search slow. Keep the heap moderate and leave the rest of the machine’s memory to the operating system.

8The HNSW Graph: How Nearest Neighbors Are Found Fast

The name sounds frightening, but the idea is friendly: use highways to get near, then local streets to arrive.

HNSW stands for Hierarchical Navigable Small World. It is a graph in which each vector is a point, connected by links to a few of its closest neighbors. The graph has several layers. The bottom layer contains every vector, with links to close neighbors. Each higher layer contains only a random sample of the vectors below it, so it is sparser, and its links span longer distances. The top layer contains very few points.

flowchart TD
    E["Entry point in the top layer"] --> L2["Top layer: few points, long jumps"]
    L2 --> L1["Middle layer: more points, shorter jumps"]
    L1 --> L0["Bottom layer: all vectors, fine search"]
    L0 --> C["Keep the num_candidates closest vectors found"]
    C --> T["Return the best k"]
    
Figure 4: A search descends the layers, moving from coarse jumps to fine steps, then keeps the closest candidates.
Everyday Analogy

Imagine driving to a small house in another country. You start on the international highway, which has few exits but covers long distances. You leave it near the right region and take a regional road with more exits. Finally you follow small streets to the exact house. You never drive through every street in the world.

How a search works

A search starts at an entry point in the top layer. From there, it repeatedly moves to whichever linked neighbor is closer to the query vector, until no neighbor is closer. That point is the best found in that layer, and it becomes the starting point in the layer below, where the same greedy walk continues with finer steps. At the bottom layer, the search does not stop at the first best point. It keeps exploring neighbors and maintains a list of the closest candidates seen so far, of a size that you control. When no better candidates can be found, it stops, and the best of the list are returned.

Why it is fast

The walk touches only a tiny part of the graph. Even with tens of millions of vectors, a typical search visits a few thousand of them. The number of steps grows slowly with the size of the collection, roughly with its logarithm, rather than in direct proportion. That is why doubling the data adds only a little to the search time, as long as the graph stays in memory.

The knobs

Build

Links per point

How many neighbors each vector links to. More links improve accuracy and give the search more paths, but enlarge the graph and slow indexing. A common default is sixteen.

Build

Construction candidate list

How many candidates are examined when linking a new vector. Larger values build a better graph, but indexing takes longer. A common default is one hundred.

Search

Number of candidates

How many candidates the bottom-layer walk keeps. Larger values find more of the true neighbors, but take more time. This is the main knob you turn at query time.

Search

The value of k

How many results you finally want. It cannot exceed the number of candidates.

The accuracy and speed trade

Every knob trades accuracy for cost. A graph built with more links and a larger construction list is better at finding true neighbors, but takes more time and memory to build. A search with more candidates finds more of the true neighbors, but takes longer. The measure of accuracy is recall: of the true k nearest neighbors, how many did the search return? A recall of ninety percent means that nine of the ten true nearest neighbors were found. Most applications aim for a recall in the high nineties and accept a small loss for large savings in time.

ChangeRecallSearch speedIndex speedMemory
More candidates at search timeHigherSlowerNo effectNo effect
More links per pointHigherSomewhat slower per step, more pathsSlowerLarger graph
Larger construction listHigherNo direct effectSlowerNo effect
Compressed vectorsSlightly lowerFasterSimilarMuch smaller
More segmentsSimilar per segmentSlower, one walk per segmentCheaper writesSimilar

One graph per segment

Because each segment has its own graph, a search runs the walk once for every segment and combines the candidates. A shard with twenty small segments does twenty walks. A shard with two large segments does two. Each walk in a small segment is quick, but the overhead adds up. This is why heavy indexing, which creates many small segments, can slow vector searches until merges catch up, and why merging read-only data into few large segments is such a helpful step.

Filters during the walk

Real searches often combine similarity with conditions such as “only in stock” or “only this customer’s documents.” Elasticsearch applies such filters during the graph walk itself: it only counts vectors of documents that pass the filter as candidates, and keeps walking until it has enough. This means the search still returns k results that all satisfy the filter, if enough exist. When a filter is very restrictive, so that very few documents pass, walking the graph becomes wasteful, and the engine switches to an exact comparison against just the passing documents, which is cheap when there are few of them.

!
Post-filtering Is a Different Thing

A filter given inside the kNN part of a request restricts the candidates during the search. A filter given only in the general query part of a request may be applied after the nearest neighbors are found, which can leave fewer than k results. Know which one you are using, and prefer the filter inside the kNN part when you need k results that all pass.

9Searching Dense Vectors

There are two ways to search a dense vector field, exact and approximate, and a powerful way to combine them with keywords.

Approximate kNN search

The main way to search an indexed dense vector field is the kNN search. You give it the field to search, a query vector, the number of results you want, and the number of candidates to consider on each shard. Optionally, you give a filter, a minimum similarity, and a boost that scales its scores. The query vector can be supplied directly, or Elasticsearch can produce it from text using a deployed embedding model, so that the client never handles vectors at all.

ParameterWhat it doesGuidance
FieldWhich dense vector field to searchMust be indexed for this kind of search
Query vector, or a way to build itThe point to search nearMust come from the same model as the stored vectors
kHow many nearest neighbors to returnSet to what the application shows or feeds onward
Number of candidatesHow many candidates each shard considersAt least k, often several times larger for better recall
FilterConditions that documents must satisfyApplied during the search, so k results pass it
Similarity thresholdMinimum closeness to acceptUse to prefer fewer results over poor ones
BoostA multiplier on the scoresUsed when combining with keyword scores

How shards and candidates interact

Each shard searches its own segments and returns its best candidates. The coordinating node then merges the lists from all shards and keeps the overall best k. Since every shard contributes, an index with many shards does more total work per search, and the candidate count applies per shard. If you raise the number of candidates while the number of shards is large, the total effort rises in proportion. Keep this in mind when tuning.

Everyday Analogy

A national talent contest holds local rounds in many towns. Each town sends its best contestants to the final, and a panel picks the overall winners. If you ask each town for its best fifty instead of its best ten, the panel sees more talent and may find a better winner, but it has more contestants to judge.

Exact search with a scoring script

The older method, still valuable, is to compute similarity exactly for a chosen set of documents inside a scoring script. It compares the query vector with the vector of every document that passes a query, and ranks them. This is exact, since no shortcut structure is used, and it works on fields that are not indexed. But its cost is proportional to the number of documents compared, so it is practical only when a filter narrows the set to thousands, not millions.

SituationBetter choice
Millions of vectors, no strong filterApproximate kNN with the graph
A filter leaves only a few thousand candidatesExact scoring over the filtered set, or approximate with a filter
You need a guaranteed exact rankingExact scoring, accepting the cost
You need to measure the quality of approximate resultsRun exact scoring on a sample, and compare
Very small indexEither, exact is simple and cheap

Hybrid search: words and meaning together

Vector search is strong on meaning and weak on exact terms, such as product codes, names, and rare words. Keyword search is the opposite. Combining them gets the best of both. A hybrid request runs a keyword query and a vector query, and merges their results into one ranking.

flowchart TD
    Q["User question"] --> L["Keyword query: words and postings lists"]
    Q --> V["Vector query: meaning and nearest neighbors"]
    L --> M["Combine rankings: weighted scores or reciprocal rank fusion"]
    V --> M
    M --> R["Final ranked results"]
    
Figure 5: Hybrid search runs a keyword query and a vector query and merges their rankings.
Method 1

Weighted sum of scores

Add the keyword score and the vector score, each multiplied by a weight. Simple, but the two scores live on different scales, so weights need tuning.

Method 2

Reciprocal rank fusion

Ignore the scores and combine the positions in each ranking, so that documents that rank well in both lists rise to the top. It needs little tuning. It may depend on your subscription level.

Method 3

Rerank the merged list

Take the combined top candidates and let a more expensive model reorder them. It improves quality at a further cost.

Paging and sizes

A kNN search returns at most k results. It is not designed for deep paging through thousands of results. If you need more, raise k, keeping in mind that the cost rises. Ordinary paging with offset and size works only within the k results. For very deep listing, use a different approach, such as a filtered keyword query or exact scoring over a narrowed set.

Practical query tips

1

Use the same model for queries and documents

Different models produce incompatible vectors.

2

Put filters inside the kNN part

That way, all k results satisfy them.

3

Set candidates above k

Start with several times k and measure recall against an exact search.

4

Combine with keywords for exact terms

Hybrid search rescues codes, names, and rare words.

5

Do not return the vector unless needed

Vectors are large. Fetching them with every hit wastes bandwidth.

10Quantization: Shrinking Vectors Without Losing Their Meaning

Vectors are big. Compression is the main way to make large collections affordable. The trick is to shrink them without shrinking the quality of the results.

flowchart LR
    A["Decimal: 4 bytes per dimension"] --> B["8-bit: about 1 byte per dimension"]
    B --> C["4-bit: about half a byte per dimension"]
    C --> D["Binary: about one bit per dimension"]
    D --> E["Smaller memory, faster search, some loss of accuracy"]
    
Figure 6: Each step of quantization stores each number with fewer bits, saving memory at a cost in accuracy.

The idea

Quantization means storing each number of a vector with fewer bits. A number such as 0.3721845 is stored as a small whole number that stands for a range of values, such as “somewhere in this band.” The comparison of two vectors is then done on these small numbers, which is faster and needs much less memory. The original number cannot be recovered exactly, but the comparison of two vectors stays close to the true one, and the ranking is usually nearly the same.

Everyday Analogy

Compressing a photograph makes the file smaller. A little compression is invisible to the eye. Heavy compression makes the image blurry. Quantization is the same trade for vectors: a little is almost free, and a lot needs care.

The common levels

LevelStorage per numberMemory savingEffect on accuracy
NoneFour bytesNoneFull precision
Eight-bitOne byteAbout four timesSmall, often negligible
Four-bitHalf a byteAbout eight timesNoticeable on some data, usually acceptable
BinaryOne bitAbout thirty timesLarger, recovered by rescoring with fuller vectors

Rescoring: getting the accuracy back

The most aggressive levels lose enough detail that the top of the ranking may be slightly wrong. The fix is rescoring. The search first finds a generous number of candidates using the compressed vectors, which is fast and cheap. Then it recomputes the exact similarity, using the original full-precision vectors read from disk, for only those candidates, and reorders them. The final list is much closer to what full precision would give, and the expensive comparison ran on a small fraction of the data. This “coarse first, fine second” pattern is why binary quantization can keep good accuracy with a tiny memory footprint.

Everyday Analogy

A hiring team skims hundreds of résumés quickly to pick a shortlist of thirty, then reads those thirty carefully. Skimming is cheap and a little sloppy, but the careful reading of the shortlist corrects most mistakes.

Quantization and the original vectors

Kept

Originals stay on disk

The full-precision vectors are usually kept, for rescoring and for rebuilding the compressed form when segments merge.

Extra

The compressed copy adds size

Disk use rises slightly, because a second, smaller copy is stored next to the original.

Memory

Only the compressed copy must be cached

The search reads the small copy, so memory needs fall, while the originals may stay on cheaper disk.

Flexible

Graph or no graph

Compression options exist both with a graph and with a plain exhaustive scan of the compressed vectors, for smaller collections.

Element types are different from quantization

Do not confuse choosing a small element type in the mapping with quantization performed by Elasticsearch. With a small element type, your model or your pipeline produces small numbers to begin with, and Elasticsearch stores exactly what you provide. With quantization, you provide normal vectors, and Elasticsearch compresses a searching copy for you and keeps the originals. The second is easier to adopt and reversible in spirit, and in recent versions it is often the default.

A numbers walkthrough

Suppose you have 100 million vectors of 384 dimensions. Stored as decimals, they need about 154 gigabytes of memory to be searched well, spread over the cluster. With eight-bit compression, this falls to about 38 gigabytes. With binary compression, to about 5 gigabytes. In the last case, a modest cluster can hold a search index that would otherwise need a large one. The price is that the search must rescore a candidate list from disk, and that a small share of results may differ from the full-precision ranking. The figures are invented, but the ratios are real.

How to choose

1

Start from the memory you can afford

Estimate the size of your vectors at each level and compare with your cache.

2

Measure recall on your own data

Compare approximate results against exact results for a sample of real queries.

3

Pick the strongest compression that still meets your quality bar

Lean on rescoring to recover accuracy at the aggressive levels.

4

Recheck after changes to the model or the data

Different embeddings compress with different losses.

i
Newer Versions Help

Recent versions choose a compressed form by default for new fields and offer improved binary methods that need less tuning. Check what your version does by default, because it may already be compressing without your having asked.

11Embedding Models: Where the Numbers Come From

The dense vector field is only as good as the vectors placed into it. Here is how vectors are made, chosen, and kept consistent.

Where the model can run

Inside

On Elasticsearch machine-learning nodes

A model is loaded into the cluster and runs next to your data. Content never leaves your environment, but the nodes need processors and memory for inference.

Service

Through an inference service

Elasticsearch calls an outside embedding service on your behalf, using a stored connection, and receives vectors back. It is easy to start, and costs money per request.

Outside

In your own application

Your loading program calls a model, then sends documents with vectors already attached. It gives full control and keeps Elasticsearch simple.

Managed

Through a field that embeds for you

A special field type can call an embedding model automatically, cut long text into chunks, and store the results, so that you index text and search text.

Embedding at indexing time

If the model runs inside or through Elasticsearch, an ingest pipeline can embed each document as it arrives. The pipeline sends the chosen text field to the model and stores the returned vector in the dense vector field. If your application embeds outside, it sends the vector as part of the document. In both cases, the same model, with the same settings, must be used for every document in the field.

Embedding at query time

At search time, the query text must be embedded by the same model. Elasticsearch can do this itself, given the model’s identifier and the text, so that clients never handle vectors. This adds the model’s latency to every search, typically tens of milliseconds for a small model on a good processor, and much more for large models or slow networks. For repeated queries, caching the query vectors saves time and money.

Everyday Analogy

A translator sits at both the entrance and the counter of a foreign shop. Goods are labeled in the shop’s language by the entrance translator, and customers’ questions are translated by the counter translator. If the two translators used different dictionaries, customers would never find what they want.

Choosing a model

QuestionWhy it matters
What language or languages will your content use?A model trained on one language does poorly on others. Multilingual models handle many, at some cost.
What kind of content: short queries, long passages, code, product data?Models are specialized. A model for web text may not suit legal documents.
How many dimensions does it produce?More dimensions mean more memory and slower search, for possibly better quality.
What is the maximum input length?Longer text than the limit is cut off, which means part of the content is never embedded.
How fast and how costly is it?Indexing millions of documents means millions of model calls.
Where can it run, and what are the data-privacy rules?Sending content to an outside service may be forbidden for sensitive data.
Which similarity does it expect?The mapping must match.
How does it perform on your data?Public benchmarks are only a guide. Test with your own queries and judgments.

Dense versus sparse models

Not all semantic models produce dense vectors. Some, such as Elastic’s own learned sparse model, produce sparse vectors: a small set of terms with weights, including related terms that were not in the text. These are stored in a different field type and searched with different queries. They tend to be more interpretable, since you can see which terms carry weight, and use less memory, while dense vectors often capture deeper meaning and work across languages. Many systems use both, together with keywords.

Chunking long content

Embedding models have a maximum input length, and even below it, one vector for a long article averages many ideas into a blur. The remedy is to cut long content into chunks, such as paragraphs or windows of a few hundred words, embed each chunk, and store each with its vector. There are two common designs. In the first, each chunk is its own document, carrying a reference to its parent. In the second, chunks are nested objects inside the parent document, each with its own vector, so that the parent is returned with the best matching chunk highlighted.

Size

Chunk size

Small chunks are precise but lose context. Large chunks keep context but blur meaning. A few hundred words is a common start.

Overlap

Overlap between chunks

Repeating a little text at the edges keeps sentences from being cut in the middle of an idea, at a cost in extra vectors.

Structure

Respect natural boundaries

Cutting at headings and paragraphs gives more meaningful chunks than cutting at fixed lengths.

Metadata

Carry the context along

Store the parent’s title, source, and permissions with each chunk, so that filtering and display work.

Model-specific details that surprise people

  • Prefixes. Some models expect a short marker before the text, one for documents and another for queries. Forgetting it lowers quality quietly.
  • Normalization. Some models return unit-length vectors and some do not. Check before choosing dot product.
  • Truncation. Text beyond the input limit is usually cut without warning.
  • Versions. A new version of a model with the same name may produce different vectors. Record the exact version used.
  • Batching. Sending many texts to the model in one call is much faster and cheaper than one at a time.
!
Never Mix Models in One Field

Vectors from two different models, or two versions of one model, do not share a map. Mixing them in one field gives results that look plausible but are wrong. Give each model its own field or its own index, and record which model made which vectors.

12Data Flow and Lifecycle of a Vector Index

A vector index is a small factory with a start and an end. Following the whole line shows where things can go wrong.

The pipeline from source to result

1

Source content

Documents, pages, products, or records come from a database, a file store, or a stream.

2

Preparation

Cleaning, splitting into chunks, and adding metadata such as source, date, and permissions.

3

Embedding

Each chunk is sent to the model, ideally in batches, and a vector comes back.

4

Indexing

Documents with vectors are sent to Elasticsearch in bulk, and vectors enter the graphs.

5

Segments and merges

Refreshes create segments, and merges combine them, rebuilding graphs.

6

Searching

Queries are embedded, nearest neighbors found, filters applied, and results merged.

7

Feedback and evaluation

Click data and relevance judgments show where quality is poor, leading to changes in models, chunks, or settings.

Everyday Analogy

A bakery takes flour and produces bread through several stations: mixing, shaping, baking, packing. A problem at an early station, such as the wrong flour, shows up as bad bread at the end. Fixing the last station will not help. The same is true of a vector index: poor chunks or the wrong model cannot be repaired by tuning the search.

When content changes

Vectors describe the content at the time they were made. If a document’s text changes, its vector must be recomputed, or it will describe the old text. A common bug is to update the text field and forget the vector, so that searches return the document for words that are no longer in it. Build the update path to re-embed whenever the embedded text changes, and consider storing a hash of the text alongside the vector, to detect when a vector is stale.

Updates and deletes at the segment level

As Chapter 7 explained, an update creates a new document in a new segment and leaves the old vector in its old graph, marked as deleted. Merges eventually clean up. In an index with frequent updates, dead vectors accumulate and merges work harder. If you can, design the data as append-mostly, with updates being rare.

Changing the model: the big move

Replacing the embedding model is the most disruptive change to a vector index. All vectors must be recomputed with the new model, and the mapping may need new dimensions or a new similarity. The safe way is a parallel build.

1

Create a new index

With the mapping that matches the new model, and a name that includes the model version.

2

Re-embed and load everything

Run the full content through the new model, and index it with settings tuned for a large load.

3

Evaluate offline

Compare results of old and new indexes on a set of representative queries.

4

Keep the two in sync while you switch

New and changed content must be embedded with both models until the change is complete.

5

Move an alias

Point the search alias at the new index, and keep the old one for a while, in case of rollback.

Merging and force merging

Merges keep the number of segments in check, and therefore the number of graph walks per search. For an index that is complete and will not receive more writes, a force merge down to a few segments makes searches faster, since fewer graphs are walked, and removes dead vectors. It also costs a lot of processing power, because graphs are rebuilt, so run it in a quiet period, and only on finished data.

Refresh interval and small segments

While loading large volumes, a short refresh interval creates many small segments, each with a small graph, and the merges that follow rebuild graphs again and again. A longer refresh interval during loading reduces this churn. Restore a sensible value when the load is over.

i
Store the Recipe With the Data

Record, for each index or document, the model name and version, the chunking rule, and the date of embedding. When quality changes, or a new model appears, this record tells you what to rebuild and how.

13Size, Performance, and Tuning

Vector search is expensive in three currencies: memory, processing time, and indexing effort. Here is where each is spent and how to save it.

Where the cost comes from

Memory

Vectors in the file cache

Millions of vectors of hundreds of numbers each. This is usually the largest and most decisive cost.

Processor

Distance calculations

Each step of a graph walk compares the query with many vectors, each comparison multiplying hundreds of numbers.

Indexing

Graph construction

Every new vector is linked into the graph by searching for its neighbors, and merges rebuild graphs.

Model

Embedding calls

One model call per chunk at indexing time and one per query at search time.

Disk

Originals and rescoring

Full vectors kept on disk, read for rescoring, add to disk use and to disk reads.

Network

Vectors in requests

Each vector is hundreds of numbers, and bulk requests full of them are large.

A numbers walkthrough for search cost

Let us use invented numbers. Suppose an exact search compares the query with 10 million vectors of 768 numbers. Each comparison needs about 768 multiplications and additions, so one query needs about 7.7 billion operations. Even on a fast processor, that takes seconds. An approximate search through a graph might compare the query with only a few thousand vectors, perhaps five thousand, which is about 3.8 million operations, roughly two thousand times fewer. That is the difference between a few seconds and a few milliseconds, and it is why the graph exists.

Everyday Analogy

Finding the most similar face in a crowd of ten million people by comparing with every person would take days. Following a chain of “this person looks similar to that person” from a starting point brings you to the closest match after a few thousand glances.

Tuning levers

LeverEffect on memoryEffect on speedTrade-off
Fewer dimensions, from a smaller modelLarge savingFaster search and indexingPossibly less nuanced meaning
QuantizationLarge savingFaster comparisonSmall loss, recovered by rescoring
Fewer, larger segmentsNoneFaster search, fewer walksCostlier merges
Longer refresh interval while loadingNoneFaster loading, fewer mergesData visible later
Zero replicas for a bulk loadNoneFaster loading, since each copy builds graphsNo safety copy during load
Lower construction effortSlightly smaller graphFaster indexingLower recall
Fewer candidates at query timeNoneFaster searchLower recall
Strong filters inside the kNN partNoneCan switch to a cheap exact checkRequires good filter design
Keep vectors out of the returned sourceSaves network and diskSmaller responsesVectors not returned unless requested
Dedicated nodes for model inferenceFrees data nodes’ memorySteadier search latencyMore machines

Indexing speed

Vector indexing is slower than text indexing, because of graph construction and, if embedding happens on the way in, model calls. To speed up a large load, embed in batches and outside the critical path if you can, use bulk requests of moderate size, lengthen the refresh interval, use zero replicas for a first load, and let the graph quality settings stay at moderate levels. Because each replica builds its own graph, the cost of replicas is real: one replica doubles the graph-building work.

Search latency

Search latency depends on whether the vectors and graphs are in the file cache. When they are, latency is set by the number of comparisons. When they are not, every step of the walk may need a disk read, and latency rises by orders of magnitude. The most common cause of slow vector search is not the query, but too little memory for the cache. After that come too many segments, too many candidates, and overly large shards.

Shard layout

Every shard runs its own walks, so more shards mean more total work per search. Choose a modest number of shards, of moderate size, and avoid spreading a small vector index over many shards. On the other hand, a single huge shard has a huge graph and long merges, and does not use several nodes’ memory. The right balance depends on the size of the index and the number of nodes.

Hardware

  • Memory first. Size the cluster so that the searched form of the vectors fits in the cache of the data nodes.
  • Modern processors. Distance calculations benefit from vector instructions of modern processors, and recent Java versions used by Elasticsearch make use of them. Old hardware wastes this.
  • Fast local disks. Rescoring and cold reads need fast random access, so solid-state drives are strongly preferred.
  • Separate roles. Keep model inference on machine-learning nodes, so that it does not compete with search for memory and processors.
i
Measure Recall and Latency Together

Speed measured without quality is meaningless, since the fastest search returns nothing useful. Always report recall next to latency, for the same settings, on realistic queries.

14Advantages, Disadvantages, and Trade-offs

Every design carries a price. Here is the honest balance sheet of searching by meaning.

Advantages

  • Finds content by meaning, not only by shared words.
  • Handles paraphrases, long natural questions, and, with the right model, many languages.
  • Works for more than text: images, audio, and products can be embedded too.
  • Approximate search stays fast on millions of vectors.
  • Combines with keywords and filters in one system.
  • Compression makes large collections affordable.
  • Provides the retrieval step for applications that use large language models.

Disadvantages

  • Needs an embedding model, which costs money, time, and care.
  • Memory-hungry, since vectors and graphs should live in cache.
  • Indexing and merging are processor-heavy.
  • Results are approximate and hard to explain.
  • Weak on exact codes, names, and rare terms without keywords.
  • Quality depends on the model, and changing the model means rebuilding everything.
  • Scores are not comparable across models and are not probabilities.
Trade-offLeaning toward qualityLeaning toward cost
Model size and dimensionsLarge model, many dimensions: nuanced, heavySmall model, few dimensions: light, less nuance
Precision of stored numbersFull precision: best accuracy, most memoryQuantized: much smaller, some loss
Candidates per searchMany: higher recall, slowerFew: faster, lower recall
Graph qualityMany links and large construction effort: better recall, slower indexingModest: faster indexing, lower recall
Chunk sizeSmall chunks: precise, many vectorsLarge chunks: fewer vectors, blurrier meaning
Exact versus approximateExact: perfect ranking, slow at scaleApproximate: fast, may miss a few
ReplicasMore: read capacity and safety, each builds graphsFewer: cheaper indexing and memory
Hybrid versus vector onlyHybrid: robust, more complexVector only: simple, weak on exact terms
Everyday Analogy

A detailed map with fine contour lines helps hikers find their way, but it takes longer to print and is heavier to carry. A rough sketch is light and quick, but may miss a cliff. The right map depends on the trail.

How ambitious should you be?

SituationRecommended stance
Small collection, thousands of documentsSimple: default settings, exact search or default graph, no compression needed
Medium collection, millions of documentsGraph with modest compression, hybrid search, measured recall
Large collection, hundreds of millions of vectorsStrong compression with rescoring, dedicated hardware, careful shard and segment planning
Exact terms matter, such as part numbersHybrid search, with keyword fields for codes
Sensitive or regulated dataModels that run inside your environment, strict access control, clear retention

15High Availability and Reliability

Vector indexes are ordinary indexes in the way they are replicated and recovered, with a few special sensitivities.

Replicas and graphs

In the standard model, each replica repeats the indexing work, so each replica builds its own graph, in its own segments. The graphs on two copies of a shard therefore differ in shape, although they hold the same vectors. Two searches served by different copies may return slightly different approximate results, because the walks follow different graphs. The differences are small, and the ranking of the best results is usually the same, but they mean that identical queries can occasionally give slightly different lists.

Everyday Analogy

Two people each draw a map of the same neighborhood from the same list of addresses. Their maps show the same houses, but the small connecting paths may be drawn differently. Two travelers following them may take slightly different routes and reach almost the same destination.

Recovery and memory

When a replica is rebuilt by copying files, vector files and graph files are copied like any other segment file. After a node restart, the file cache is cold: vectors and graphs must be read from disk again, and searches are slow until the cache warms. For large vector indexes, this warm-up can take minutes or longer, and search latency in that period may be many times higher. Plan restarts accordingly: restart one node at a time, and let each node warm up before moving on.

FailureEffect on vector searchResponse
A data node crashesReplicas take over, cold caches on the nodes that pick up trafficExpect a latency bump, let caches warm
A node restartsIts cache is empty, searches on its shards are slow at firstRolling restarts, one node at a time, and warm-up time
Memory pressureThe operating system evicts vector pages, and latency spikesMore memory, compression, or fewer vectors per node
Embedding service is unavailableNew documents cannot be embedded, and text queries cannot be embeddedRetry with backoff, queue documents, fall back to keyword search
Model changed by mistakeQuery vectors no longer match stored vectors, results degrade quietlyPin model versions, monitor quality, keep a rollback index
Segment corruptionThe affected copy is failed and rebuilt from another copyKeep at least one replica, take snapshots
Upgrade of ElasticsearchGraph and file formats may change with the underlying libraryRead release notes, test on a copy, reindex if required

Designing for resilience

1

Keep at least one replica for important indexes

It protects against node loss and serves searches while another copy recovers.

2

Size memory with headroom

If a node fails, the remaining nodes must hold more vectors in their caches.

3

Have a keyword fallback

If embedding is unavailable, a plain keyword search keeps the application usable.

4

Snapshot regularly

Re-embedding millions of documents is slow and costly, so protect the vectors themselves.

5

Version everything

Pin the model, the mapping, and the chunking rule, and record them with the index.

!
Re-embedding Is Expensive

Losing the vectors means paying again for every model call. For large collections, that can cost days of time and real money. Snapshots of vector indexes are cheap insurance compared with recomputing them.

16Security and Privacy Considerations

A vector looks like harmless numbers. It is not. It carries the meaning of your content, and the path to it has its own risks.

Vectors leak meaning

An embedding is a compressed description of the content. Research has shown that, with enough effort, parts of the original text can be reconstructed from its embedding, or at least that sensitive attributes can be inferred. You should therefore treat vectors with the same sensitivity as the text they came from. If the text is confidential, so are its vectors, in the index, in snapshots, and in backups.

Everyday Analogy

A detailed description of a secret document, even without the document itself, still reveals a lot. The description needs the same lock as the document.

Access control still applies

Index level

Restrict who can search

Use roles to limit which users can read which indexes. Similarity search does not bypass permissions.

Document level

Permissions per document

Where your subscription supports it, restrict which documents a user may see. Test that kNN results respect it. In search designs with filters, put the permission in the filter, inside the kNN part.

Field level

Hide the vector field

Most users need results, not the raw vectors. Do not grant access to the vector field, and do not return it.

Metadata

Carry permissions in chunks

When documents are chunked, each chunk must inherit the permissions of its parent, or a chunk may leak.

The embedding path is a data path

When embedding happens in an outside service, your content leaves your environment. Check the provider’s terms: whether data is stored, used for training, or logged, where it is processed, and how it is protected. For regulated or confidential data, prefer models that run inside your own cluster or network. Protect the credentials used to call the service, keep them in secure storage, rotate them, and give each application its own.

Risks specific to retrieval for language models

When vector search feeds a large language model, a further set of risks appears. The retrieved text becomes part of the model’s input. If a retrieved document contains hidden instructions, such as text that tells the model to ignore its rules or reveal secrets, the model may obey them. This is called prompt injection through retrieved content. Reduce the risk by controlling what enters the index, marking retrieved text clearly as data and not as instructions, limiting what the model is allowed to do, and reviewing outputs where the stakes are high.

Poisoning and quality attacks

Someone who can add documents to the index can also try to influence what is retrieved, by writing content designed to be close to popular queries. If your index accepts content from the public, treat it as untrusted: moderate it, limit who can write, and separate it from trusted content.

Deletion and retention

When a document is deleted, its vector remains in the segment’s files until a merge removes it, and older history may be kept for recovery. Snapshots also keep copies. For privacy requests to erase personal data, know how long these copies last, and plan deletion and merging accordingly. Remember that vectors of derived chunks must be deleted as well.

Resource abuse

Vector search is costly. A user, or an attacker, who can send unlimited queries with huge candidate counts or large k can burn processors and memory. Set limits on k and candidates, add rate limits and timeouts in front of search endpoints, and separate heavy workloads from interactive ones.

i
Do Not Skip the Basics

Turn on authentication and encryption, even for clusters that seem internal. Encrypt data at rest on the nodes that hold vectors, and secure the snapshot storage. Many exposures of indexed data start with a cluster that was described as “only internal.”

17Monitoring, Logging, and Metrics

Vector search can fail in a way that keyword search rarely does: it can keep answering quickly while quietly getting worse. Watch both speed and quality.

Windows onto the index

WindowWhat it showsUse it to
Index disk usage analysisBytes used by vectors and graphs, by fieldSee what vectors cost on disk
Segment listingNumber and size of segmentsSpot too many small segments
Index and node statisticsSearch and indexing times, merge activity, and in newer versions the number of vectorsTrack trends
Profile option on a searchTime in the vector search, and in newer versions how many vectors were comparedSee what one query costs
Slow logsSearches and indexing operations over a time thresholdFind expensive queries
Machine-learning statisticsModel deployments, inference times, queuesWatch embedding latency and throughput
Operating system metricsMemory, cache, disk reads, processorSee whether the cache is holding the vectors

Metrics to chart

MetricWhat it tells youWarning sign
Search latency percentilesHow long queries take, including the slow tailA rising slow tail
Recall on a fixed test setHow many true neighbors are foundAny drop after a change
Disk reads during searchesWhether vectors are served from cacheHigh reads on vector nodes
Segments per shardNumber of graph walks per searchGrowth without merges catching up
Merge time and throttlingWhether merges keep up with writesMerges constantly running
Indexing throughputSpeed of loading, including embeddingSudden drops
Embedding latency and errorsHealth of the model pathTimeouts, rate limits, rising error counts
Share of deleted documentsDead vectors in graphsA large share for a long time
Free memory for the file cacheHeadroom for vectorsShrinking headroom
Result quality signalsClicks, ratings, and reviewed samplesA decline in useful results

Measuring quality: recall and relevance

There are two different questions. Recall asks whether the approximate search finds what the exact search would find. You can measure it by taking a sample of real queries, running both the approximate search and an exact scoring search, and counting how many of the exact top results appear in the approximate top results. Relevance asks whether the results are actually useful to people. It needs human judgments or behavior data, and depends on the model and the chunks more than on the search settings. Both matter, and they are affected by different changes.

1

Build a test set

Collect a few hundred real queries, with judgments of which documents are good answers where possible.

2

Measure recall against exact search

This tells you whether the search settings and compression are losing true neighbors.

3

Measure relevance against judgments

This tells you whether the model, chunks, and hybrid mix are helping people.

4

Repeat after every change

Model, chunking, compression, and settings changes can each move both numbers.

Reading the patterns

Healthy

Steady latency, high recall

Vectors are in the cache, segments are few, and results are judged useful.

Cache-starved

Slow tail, high disk reads

Vectors do not fit in memory. Compress, add memory, or reduce the data on the node.

Fragmented

Many segments, slower searches

Heavy writes create many graphs. Lengthen refresh and let merges catch up.

Drifting

Speed fine, quality declining

Check whether the model or its input changed, whether vectors are stale, and whether recall dropped after a setting change.

Overloaded

Embedding queue growing

Model inference cannot keep up. Add capacity, batch requests, or slow the load.

Dead weight

Many deleted documents

Update-heavy data leaves dead vectors. Consider the data model, and let merges clean up.

i
Alerts Worth Having

Alert on a rising slow tail of search latency, on rising disk reads on vector nodes, on falling recall in a scheduled test, on embedding errors and timeouts, on segment counts that keep growing, and on the free memory left for the file cache.

18Design Patterns and Anti-patterns

Good habits make vector search accurate and affordable. Bad habits are behind most disappointing results and most surprising bills.

Patterns that work

1

Hybrid by default

Combine keyword and vector search, so exact terms and meaning both count. Pure vector search is the exception, not the rule.

2

Chunk with care and carry metadata

Cut long content along natural boundaries, and store title, source, date, and permissions with every chunk.

3

Filters inside the kNN part

Apply permissions and business conditions during the search, so that every returned result satisfies them.

4

Compress, then rescore

Use quantization to fit memory, and let rescoring with full vectors recover accuracy.

5

Alias-based model switching

Build a new index for each model version and move an alias when the new one is proven.

6

A fixed evaluation set

Keep a set of queries and judgments, and run it after every change to model, chunking, compression, or settings.

7

Batch and isolate embedding

Embed in batches, on dedicated machines or services, with retries and queues, so search stays smooth.

Everyday Analogy

A good research librarian uses both the card catalog for exact titles and her understanding of topics for vague requests. She knows which shelf each section is on, keeps notes on who may read restricted books, and tests her methods by asking whether readers found what they wanted.

Anti-patterns to avoid

ANTI-PATTERN 01Avoid
What people do

They mix vectors from different models, or different versions of one model, in the same field, for example after a quiet upgrade of the embedding service.

Why it hurts

Vectors from different models live on different maps. Results look plausible but are wrong, and the problem is hard to notice.

Better approach

Pin model versions, give each model its own field or index, and rebuild fully when the model changes.

ANTI-PATTERN 02Avoid
What people do

They embed whole long documents as a single vector, or let the model silently cut the text at its input limit.

Why it hurts

The vector blurs many ideas together, or ignores the end of the document. Searches miss specific passages.

Better approach

Chunk documents into meaningful passages within the model’s limit, and embed each one.

ANTI-PATTERN 03Avoid
What people do

They use pure vector search for queries that are mostly exact codes, names, or identifiers.

Why it hurts

Embeddings blur exact strings. A search for one part number may return similar-looking ones, but not the exact one.

Better approach

Use keyword fields for exact values, and combine with vector search for descriptive text.

ANTI-PATTERN 04Avoid
What people do

They give the Java heap almost all of the machine’s memory, leaving little for the operating system’s file cache.

Why it hurts

Vectors and graphs cannot stay in memory, so searches read the disk at every step of the graph walk, and latency explodes.

Better approach

Keep the heap moderate, size memory so the searched form of the vectors fits in the cache, and compress if needed.

ANTI-PATTERN 05Avoid
What people do

They tune settings by trying a few queries and judging the results by eye.

Why it hurts

Small samples hide problems. A change that helps three queries may hurt hundreds.

Better approach

Keep a fixed test set, measure recall and relevance, and compare before and after each change.

ANTI-PATTERN 06Avoid
What people do

They update the text of documents but do not recompute their vectors.

Why it hurts

Vectors describe the old text. Documents are returned for meanings that they no longer have.

Better approach

Re-embed whenever the embedded text changes, and store a hash of the text to detect stale vectors.

ANTI-PATTERN 07Avoid
What people do

They return the vector with every search hit, and fetch source fields that include vectors in every request.

Why it hurts

Each vector is hundreds of numbers. Responses become huge, and network and processing time are wasted.

Better approach

Keep vectors out of the returned source and request them only when needed.

ANTI-PATTERN 08Avoid
What people do

They spread a small vector index over many shards, or request enormous k and candidate values “to be safe.”

Why it hurts

Every shard runs its own graph walks, and large candidate counts multiply the work. Latency and cost rise for little gain.

Better approach

Use few, moderately sized shards, and set candidates by measuring the recall you actually need.

19Best Practices and Common Mistakes

A short list you could hand to a new teammate on their first day.

Best practices

Model

Choose and test the model on your data

Benchmarks are a guide. Your own queries decide.

Mapping

Match dimensions and similarity

Follow the model’s documentation exactly.

Content

Chunk and label

Meaningful chunks with metadata for filtering and display.

Search

Go hybrid

Keywords for exact terms, vectors for meaning.

Memory

Plan for the cache

Moderate heap, compression, and enough RAM for the searched vectors.

Quality

Measure recall and relevance

Repeat after every change.

Change

Version and switch by alias

New model, new index, then move the alias.

Safety

Protect vectors like text

Access control, encryption, and retention apply to vectors too.

Common mistakes

  • Treating vector search as magic. It is only as good as the model, the chunks, and the data.
  • Forgetting that scores are relative. A high score is not proof of relevance, and scores differ between models.
  • Setting the wrong number of dimensions. The field must match the model exactly, or indexing fails.
  • Skipping normalization when using dot product. The ranking is then distorted.
  • Ignoring model input limits. Text beyond the limit is not embedded.
  • Forgetting the prefixes some models need. Quality drops quietly.
  • Using a post-filter and expecting k results. Filters given outside the kNN part can leave fewer results.
  • Neglecting the cold cache after restarts. Latency is high until vectors are read back into memory.
  • Assuming the mapping can be changed in place. Dimensions and similarity generally cannot.

Myths versus facts

MythFact
Vector search replaces keyword search.Each is strong where the other is weak, and hybrid search combines them.
A dense vector field creates the embeddings.It stores them. A separate model creates them.
More dimensions always means better results.More dimensions cost more, and may help only modestly. The model matters more.
Approximate search returns wrong answers.It returns almost all of the true neighbors, and recall can be measured and tuned.
Vectors are anonymous numbers.They carry the meaning of the content and can leak information.
Compression ruins quality.Moderate compression is nearly free, and rescoring recovers most of the rest.
Similarity scores are probabilities.They are model-dependent closeness values used for ranking.
I can swap the model and keep the old vectors.Vectors from different models are incompatible. Everything must be recomputed.
!
A Golden Rule

The quality of vector search is decided upstream: by the model, by how content is chunked, and by what is kept in the index. Tuning the search settings can only recover what was already there. Spend your effort on the inputs first.

20Real-World and Industry Examples

Where does the dense vector field quietly change what users can do?

Many well-known organizations have said publicly that Elasticsearch is part of their systems, including Wikipedia’s search, Netflix, Uber, and Stack Overflow. They rarely publish how they use vectors, so the scenarios below are typical patterns for such workloads, not descriptions of anyone’s private configuration.

Retrieval for question answering with a language model

One of the most common uses today is to give a large language model the right information to answer a question. The pattern is often called retrieval-augmented generation. The documents of a knowledge base are chunked and embedded into a dense vector field. When a user asks a question, the question is embedded, the nearest chunks are retrieved, and both the question and the chunks are handed to the language model, which writes an answer based on them.

flowchart LR
    U["User question"] --> E["Embed the question"]
    E --> K["kNN search in Elasticsearch"]
    K --> C["Top chunks of text"]
    C --> P["Prompt with the question and the chunks"]
    P --> L["Language model writes the answer"]
    L --> A["Answer with sources"]
    
Figure 7: A retrieval flow for question answering: embed, retrieve the nearest chunks, and hand them to a language model.
Everyday Analogy

A student answering an exam question with an open book first finds the right pages, and then writes the answer from them. The search finds the pages, and the language model is the student. If the wrong pages are found, even a very good student writes a wrong answer.

Online store: search by intent

A retailer of the size of Amazon or eBay lets shoppers type “something warm for a winter camping trip.” Product titles and descriptions are embedded, and the search combines vector similarity with keyword matching and filters for size, price, and stock. Exact brand names and model numbers are handled by the keyword side, while descriptive queries are handled by the vector side.

Support center: answers from past tickets and manuals

A software company indexes help articles and resolved tickets in chunks. Agents and customers ask questions in their own words, and the system retrieves relevant passages. Permissions are stored with every chunk, and applied as filters inside the vector search, so that customers only see public articles.

Media catalog: “more like this”

A streaming service represents each title by a vector built from its description, genres, and viewer behavior. Finding similar titles means finding the nearest vectors to the one a viewer just watched, with filters for language, rating, and availability in the viewer’s country.

Image and product similarity

A marketplace embeds product photos with an image model. A shopper uploads a picture, its vector is computed, and the nearest product vectors are returned. Compression makes it practical to hold hundreds of millions of image vectors in memory.

Duplicate and near-duplicate detection

A content platform finds articles that are nearly the same by searching each new article’s vector against existing ones, with a similarity threshold. Only very close neighbors are treated as duplicates, and humans review the borderline ones.

Multilingual site search

A travel company serves visitors in many languages. A multilingual embedding model lets a question in one language find pages written in another, without translation. The team combines it with keyword search in each language for names of places and hotels.

i
The Common Thread

In every example, the winning ideas are the same: a model matched to the content, chunks with useful metadata, filters applied inside the vector search, hybrid ranking for exact terms, compression to fit memory, and constant measurement of both recall and relevance.

21Frequently Asked Questions

Short answers to the questions that come up most often.

Q1What is a dense vector field in one sentence?
It is a field type that stores, for each document, a fixed-length list of numbers produced by an embedding model, and lets Elasticsearch find the documents whose lists lie closest to a query list, meaning the documents most similar in meaning.
Q2Does Elasticsearch create the vectors?
The field only stores them. A separate embedding model creates them. That model can run inside Elasticsearch, be called through an inference service, or run in your own application.
Q3How many dimensions should I use?
Exactly as many as your embedding model produces. The field must match, or indexing fails. Choosing a model with fewer dimensions saves memory and time, but may capture less nuance.
Q4Which similarity should I choose?
Use the one recommended for your model. Cosine is the most common for text. Dot product is fastest, and equals cosine when vectors are normalized to length one. Straight-line distance and maximum inner product suit models trained for them.
Q5What is kNN search?
It is a search that returns the k stored vectors nearest to a query vector. Elasticsearch normally does this approximately, using a graph, which makes it fast on millions of vectors.
Q6What does “approximate” mean, and can I trust it?
It means the search may occasionally miss a true nearest neighbor, in exchange for far greater speed. The share of true neighbors found is called recall, and you can measure it against an exact search and tune it.
Q7What is the number of candidates for?
It controls how many close vectors each shard examines before returning its best. More candidates give higher recall but take longer. It must be at least k.
Q8Why must query and document vectors come from the same model?
Each model has its own map of meaning. Coordinates from one model are meaningless on another’s map, so mixing them gives wrong results that still look plausible.
Q9Can a document have several vectors in one field?
Not in the standard arrangement. Cut the document into chunks, and index each as its own document, or use nested objects, each holding a vector.
Q10How much memory do I need?
Roughly the number of vectors times the bytes per number times the dimensions, plus some graph overhead, and it should fit in the operating system’s file cache. Quantization can cut this by four times or much more.
Q11What is quantization?
Storing each number with fewer bits to save memory and speed up comparison. The original vectors are usually kept on disk and can be used to rescore the best candidates for higher accuracy.
Q12Can I combine vector search with filters?
Yes. Filters given inside the kNN part are applied during the graph search, so all k results satisfy them. Filters applied only after the search may leave fewer than k results.
Q13What is hybrid search?
Running a keyword query and a vector query together and merging their rankings, either by adding weighted scores or by combining positions with a method such as reciprocal rank fusion. It handles both exact terms and meaning.
Q14Why is indexing vectors slow?
Each new vector must be linked into the graph by searching for its neighbors, and merges rebuild graphs. On top of that, embedding the content may need a model call for every chunk.
Q15Why is my first search after a restart so slow?
The file cache is empty, so vectors and graphs must be read from disk. Latency falls as the cache warms. Restart one node at a time and allow warm-up.
Q16What happens if I change the embedding model?
All vectors must be recomputed with the new model, because old vectors are meaningless to it. Build a new index, load and evaluate it, then move an alias to it.
Q17Are vectors safe to treat as anonymous numbers?
No. They carry the meaning of the content and can leak information. Protect them with the same access control, encryption, and retention rules as the original text.
Q18Can I use it for images?
Yes, with an image embedding model that turns pictures into vectors. The field stores and searches them in the same way as text vectors.
Q19Do replicas return identical results?
Almost. Each replica builds its own graph, so approximate searches on different copies can differ slightly at the edges of the result list.
Q20Do options and defaults change between versions?
Yes, quite a lot. Limits on dimensions, default compression, available element types, and related features have changed over the releases. Always confirm in the documentation for the exact version you run.

22Summary and Key Takeaways

If you skim only one part of this guide, make it this one.

The dense vector field lets Elasticsearch search by meaning. It stores, for each document, a fixed-length list of numbers made by an embedding model, indexes those lists in a layered graph, and finds the nearest ones to a query in milliseconds. It costs memory, indexing effort, and care, and it pays back with search that understands paraphrases, works across languages, and feeds language-model applications.

Key Takeaways

  • What it is: a field holding one fixed-length vector per document, produced by an embedding model, searched by nearest-neighbor similarity.
  • How closeness is measured: choose the metric your model recommends, typically cosine or dot product for normalized vectors, and remember that scores are for ranking, not probabilities.
  • How search stays fast: an HNSW graph per segment lets a search visit a few thousand vectors instead of millions, at the price of approximate results whose recall you can measure and tune.
  • How it fits in memory: vectors and graphs must live in the operating system’s file cache, so keep the heap moderate, and use quantization with rescoring to shrink memory many times over.
  • How to combine it: put filters inside the kNN search, and combine vectors with keywords in hybrid search, so both meaning and exact terms count.
  • How to keep it healthy: keep segments few, plan for cold caches after restarts, embed in batches, re-embed when text changes, and switch models by building a new index and moving an alias.
  • How to keep it safe and good: treat vectors as sensitive as the text, guard the embedding path, and measure both recall and relevance on a fixed test set after every change.