You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Document fine-grained IVF search controls and custom index names (#220)
* Document fine-grained nprobes, distance_range, bypass_vector_index, and custom index names
- Replace Search Configuration bullets with markdown tables covering
core knobs and per-index-type nprobes guidance
- Document minimum_nprobes / maximum_nprobes with a note on adaptive
partition scanning under filtered queries
- Add Advanced Search Controls subsection covering distance_range()
for thresholded retrieval and bypass_vector_index() for recall
measurement against flat-scan ground truth
- Document that vector indexes support custom names via name=...,
clarifying that the _idx suffix is a default convention
- Add four runnable pytest snippet tests backing the new examples
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Update snippets
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
You can create and manage multiple vector indexes on any Lance dataset. LanceDB offers two kinds of vector indexing algorithms: **Inverted File (IVF)** and **Hierarchical Navigable Small World (HNSW)**.
@@ -144,17 +148,65 @@ Search using a random 1,536-dimensional embedding.
144
148
145
149
#### Search Configuration
146
150
147
-
The previous query uses:
151
+
Core knobs available on a vector search call:
148
152
149
-
-`limit`: number of results to return
150
-
-`nprobes`: number of IVF partitions to scan. LanceDB auto-tunes this by default.
151
-
-`ef`: primarily relevant for HNSW-backed IVF indexes such as `IVF_HNSW_FLAT` and `IVF_HNSW_SQ`; start around `1.5 * k` (where `k=limit`) and increase up to `10 * k` for higher recall.
152
-
-`nprobes` by index type:
153
-
-`IVF_HNSW_FLAT` and `IVF_HNSW_SQ`: usually keep auto-tuned `nprobes`, then tune `ef` first. For filtered search (`where(...)`), expect higher latency variance.
154
-
-`IVF_RQ`: keep auto-tuned `nprobes`; increase only when recall is insufficient.
155
-
-`IVF_PQ`: keep auto-tuned `nprobes`; increase when recall is insufficient. Often preferred over `IVF_RQ` when `dimension <= 256`.
156
-
-`refine_factor`: reads additional candidates and reranks in memory
157
-
-`.to_pandas()`: converts the results to a pandas DataFrame
153
+
| Parameter | Description |
154
+
| :--- | :--- |
155
+
|`limit`| Number of results to return (`k`). |
156
+
|`nprobes`| Shorthand that sets both `minimum_nprobes` and `maximum_nprobes` to the same value. LanceDB auto-tunes this by default. |
157
+
|`minimum_nprobes`| Partitions that are *always* scanned. Higher values raise recall at the cost of latency. |
158
+
|`maximum_nprobes`| Upper bound on partitions scanned. The partitions above `minimum_nprobes` are only searched if the initial pass does not return enough results — useful for narrow filters. Set to `0` to remove the cap. |
159
+
|`ef`| HNSW search-time exploration factor. Relevant for `IVF_HNSW_FLAT` and `IVF_HNSW_SQ`; start around `1.5 * k` and increase up to `10 * k` for higher recall. |
160
+
|`refine_factor`| Reads additional candidates and reranks them in memory to recover recall lost to quantization. |
161
+
162
+
<Note>
163
+
**Filtered queries and adaptive nprobes.** When a `where(...)` filter is active, LanceDB starts by scanning `minimum_nprobes` partitions and only extends toward `maximum_nprobes` if fewer than `limit` rows survive the filter. Setting `minimum_nprobes == maximum_nprobes` (or calling `nprobes(n)`) disables this adaptive behavior and fixes the partition count.
|`IVF_HNSW_FLAT`, `IVF_HNSW_SQ`| Keep the auto-tuned `nprobes`, then tune `ef` first. Expect higher latency variance under filtered search. |
177
+
|`IVF_RQ`| Keep auto-tuned `nprobes`; raise only when recall is insufficient. |
178
+
|`IVF_PQ`| Keep auto-tuned `nprobes`; raise when recall is insufficient. Often preferred over `IVF_RQ` when `dimension <= 256`. |
179
+
180
+
#### Advanced Search Controls
181
+
182
+
These controls are useful for thresholded retrieval, recall measurement, and working around index-level metric constraints.
183
+
184
+
| Method | Description |
185
+
| :--- | :--- |
186
+
|`distance_range(lower_bound, upper_bound)`| Return only rows whose distance falls within `[lower_bound, upper_bound)`. Either bound is optional. Useful for near-duplicate detection or "close-enough" matching. |
187
+
|`bypass_vector_index()`| Skip the ANN index and perform an exhaustive (flat) scan. Primary uses: (1) compute ground-truth results to measure ANN recall@k, and (2) query with a metric the index was not built for (e.g., a non-cosine query on a multivector column). |
Flat search is $O(n)$ — reserve `bypass_vector_index()` for sampled recall measurements or small tables, not production queries.
209
+
</Warning>
158
210
159
211
## Example: Construct an HNSW Index
160
212
@@ -238,11 +290,21 @@ Navigate to your table page - the "Index" column shows index status. It remains
238
290
239
291
### Option 2: Use the API
240
292
241
-
Use `list_indices()` and `index_stats()` to check index status. The index name is formed by appending "\_idx" to the column name. Note that `list_indices()` only returns information after the index is fully built.
293
+
Use `list_indices()` and `index_stats()` to check index status. **By default**, the index name is formed by appending `_idx` to the column name (e.g., a `keywords_embeddings` column produces `keywords_embeddings_idx`). Note that `list_indices()` only returns information after the index is fully built.
242
294
To wait until all data is fully indexed, you can specify the `wait_timeout` parameter on `create_index()` or call `wait_for_index()` on the table.
The `{column}_idx` suffix is a default convention, not the only supported naming path. Pass `name=...` to `create_index()` to override it — useful when you want to manage multiple indexes on the same column (for example, side-by-side `IVF_PQ` and `IVF_HNSW_SQ` builds) or when you script index replacement by name. Once set, `list_indices()`, `index_stats(name)`, and `wait_for_index([name])` all reference the custom name.
exportconst PyVectorIndexCustomName ="# Override the default `{column}_idx` convention by passing `name=...`.\ntable.create_index(\n metric=\"cosine\",\n vector_column_name=\"keywords_embeddings\",\n name=\"my_custom_index\",\n)\ntable.wait_for_index([\"my_custom_index\"])\nprint(table.index_stats(\"my_custom_index\"))\n";
54
+
55
+
exportconst PyVectorIndexDistanceRange ="# Only return results whose distance falls within [0.0, 0.5).\n# Useful for near-duplicate detection or thresholded similarity search.\n(\n table.search(np.random.random(128))\n .distance_range(lower_bound=0.0, upper_bound=0.5)\n .limit(10)\n .to_pandas()\n)\n";
56
+
57
+
exportconst PyVectorIndexNprobes ="# Always scan 10 partitions; scan up to 50 only if the initial pass\n# returns fewer than `limit` results (common with narrow filters).\n(\n table.search(np.random.random(128))\n .minimum_nprobes(10)\n .maximum_nprobes(50)\n .where(\"id > 100\")\n .limit(5)\n .to_pandas()\n)\n";
0 commit comments