mirror of
https://github.com/lancedb/lancedb.git
synced 2026-10-15 16:22:27 +00:00
Move the public website pages into `docs/web` beside the SDK, with
shared navigation and executable example sources in `docs/web-tests`.
The combined website is assembled by
[lancedb/docs#355](https://github.com/lancedb/docs/pull/355), with six
Enterprise replacements from
[lancedb/sophon#7681](https://github.com/lancedb/sophon/pull/7681).
This includes Function guidance, runnable Quickstarts, regenerated
snippets, production contact/demo fixes, the legacy SQL route, and the
LeRobot redirect. LeRobot remains attributed to Geneva; all 34 Geneva
pages remain in the docs repository until Function officially launches.
Materialized-view guidance follows the full rebuild refresh introduced
by #4373: local refresh writes the complete result, has no `full`
argument, supports `source_version`, and no longer requires stable row
IDs. Deployment SQL refresh options and stable-ID setup are qualified by
version/configuration. Function input guidance distinguishes ordinary
stored columns from computed inputs supported by newer deployments.
**Validation:** independently accepted local checks include 95 Python
tests (real Enterprise excluded), eight TypeScript tests, Rust
Quickstart, snippet parity, typos, deterministic assembly, Mint
validation and links/anchors/redirects. The combined baseline retains
all 181 production routes and 17 legacy redirects. Examples ran locally
against source-built Python SDK 0.40.0b13; existing GitHub workflows do
not run `docs/web-tests`. New main at `069b2f7d` is 0.41.0b0 and adds
computed Function inputs; that SDK was not exercised by the accepted
tests. Latest prose corrections receive focused site validation.
**Merge/rollout:** merge this and #7681 before #355's combined CI, which
reads producer `main`. This is migration infrastructure: section
overlays, source-owned skills and automatic versioned paired releases
remain follow-ups. The current manual publisher is transitional. Hosted
validation, a supported SDK/Enterprise release pair and a real
Enterprise walkthrough remain pending.
Production Mintlify watches `lancedb/docs:deploy-freeze`, directory
`docs`; preserve that source through review. The separate SDK GitHub
Pages reference workflow rebuilds on main merges.
**Updated-head CI (9a50f8db):**
[Typos](https://github.com/lancedb/lancedb/actions/runs/37654185443/job/112904990558),
[PR
title](https://github.com/lancedb/lancedb/actions/runs/37654179507/job/112904974595)
and
[Aikido](https://app.aikido.dev/featurebranch/scan/215386145?groupId=74229)
pass. Critical findings in the example lockfiles were patched: all Sharp
copies use 0.35.5, protobufjs 7.6.6, tar 7.5.22, quinn-proto 0.11.19,
zerovec 0.11.8 and zerovec-derive 0.11.6. The SDK's product dependencies
are unchanged. The revised lockfiles pass eight TypeScript examples,
HuggingFace decode/resize/crop/rescale/normalize plus AVIF roundtrip,
and Rust Quickstart. Aikido passing does not mean every advisory is
cleared; npm still reports 29 high and five moderate advisories in the
example dependency graph. No scanner bypass or suppression was added.
The Function prose correction passes combined/standalone Mint,
deterministic assembly, routes and assets. The revised 325-file site
checksum is
`175bec06864abb400dd292e667ba93448c0479b8359fd7bf6146afabf9040647`. This
PR remains open for independent review; further merges are on hold.
---------
Co-authored-by: Brendan Clement <brendan.clement@lancedb.com>
254 lines
9.5 KiB
Plaintext
254 lines
9.5 KiB
Plaintext
---
|
|
title: "Scalar Indexes"
|
|
sidebarTitle: "Scalar Index"
|
|
description: "Learn how to use scalar indexes in LanceDB for efficient metadata filtering and query optimization."
|
|
icon: "tree"
|
|
---
|
|
|
|
import {
|
|
PyScalarIndexBuild as ScalarIndexBuild,
|
|
PyScalarIndexWait as ScalarIndexWait,
|
|
PyScalarIndexOptimize as ScalarIndexOptimize,
|
|
PyScalarIndexFilter as ScalarIndexFilter,
|
|
PyScalarIndexPrefilter as ScalarIndexPrefilter,
|
|
PyScalarIndexUuidType as ScalarIndexUuidType,
|
|
PyScalarIndexUuidData as ScalarIndexUuidData,
|
|
PyScalarIndexUuidTable as ScalarIndexUuidTable,
|
|
PyScalarIndexUuidWait as ScalarIndexUuidWait,
|
|
PyScalarIndexUuidUpsert as ScalarIndexUuidUpsert,
|
|
PyScalarIndexNestedFields as ScalarIndexNestedFields,
|
|
} from '/snippets/indexing.mdx';
|
|
|
|
Scalar indexes organize data by scalar attributes (e.g., numbers, categories) and enable fast filtering of vector data. They accelerate retrieval of scalar data associated with vectors, thus enhancing query performance.
|
|
|
|
LanceDB supports four types of scalar indexes:
|
|
|
|
- `BTREE`: Stores column data in sorted order for binary search. Best for columns with many unique values.
|
|
- `BITMAP`: Uses bitmaps to track value presence. Ideal for columns with few unique values (e.g., categories, tags).
|
|
- `LABEL_LIST`: Special index for `List<T>` and `LargeList<T>` columns of primitive values supporting `array_contains_all` and `array_contains_any` queries.
|
|
- `FM`: FM-Index over string or binary columns that accelerates substring search via `contains(col, 'needle')`.
|
|
|
|
<Tip title="Working with scalar indices">
|
|
Scalar indices serve as a foundational optimization layer, accelerating filtering across diverse search workloads. They can be combined with:
|
|
|
|
- Vector search (prefilter results using metadata)
|
|
- Full-text search (combining keyword matching with structured filters)
|
|
- SQL scans (optimizing WHERE clauses on scalar columns)
|
|
- Key-value lookups (enabling rapid primary key-based retrievals)
|
|
</Tip>
|
|
|
|
## Choosing the Right Index Type
|
|
|
|
| Data Type | Filter | Index Type |
|
|
|:----------------------------------------------------------------|:------------------------------------------|:-------------|
|
|
| Numeric, String, Temporal | `<`, `=`, `>`, `in`, `between`, `is null` | `BTREE` |
|
|
| Boolean, numbers or strings with fewer than 1,000 unique values | `<`, `=`, `>`, `in`, `between`, `is null` | `BITMAP` |
|
|
| List of low cardinality of numbers or strings | `array_has_any`, `array_has_all` | `LABEL_LIST` |
|
|
| String or binary (`Utf8`, `LargeUtf8`, `Binary`, `LargeBinary`) | `contains(col, 'needle')` | `FM` |
|
|
|
|
## Scalar Index Operations
|
|
|
|
### 1. Build the Index
|
|
|
|
You can create multiple scalar indexes within a table. By default, the index will be `BTREE`, but you can always configure another type like `BITMAP`
|
|
|
|
<CodeGroup>
|
|
<CodeBlock filename="Python" language="Python" icon="python">
|
|
{ScalarIndexBuild}
|
|
</CodeBlock>
|
|
</CodeGroup>
|
|
|
|
<Note title="LanceDB Enterprise">
|
|
If you are using LanceDB Enterprise, the `create_scalar_index` API returns immediately, but the building of the scalar index is asynchronous. To wait until all data is fully indexed, you can specify the `wait_timeout` parameter on `create_scalar_index()` or call `wait_for_index()` on the table.
|
|
</Note>
|
|
|
|
### 2. Check Index Status
|
|
|
|
<CodeGroup>
|
|
<CodeBlock filename="Python" language="Python" icon="python">
|
|
{ScalarIndexWait}
|
|
</CodeBlock>
|
|
</CodeGroup>
|
|
|
|
`wait_for_index(...)` waits until the named scalar indexes exist and `index_stats(...)` reports `num_unindexed_rows == 0`. If a table is receiving steady writes, that fully indexed state may not stabilize before the timeout.
|
|
|
|
### 3. Update the Index
|
|
|
|
Updating the table data (adding, deleting, or modifying records) requires that you also update the scalar index. This can be done by calling `optimize`, which will trigger an update to the existing scalar index.
|
|
|
|
<CodeGroup>
|
|
<CodeBlock filename="Python" language="Python" icon="python">
|
|
{ScalarIndexOptimize}
|
|
</CodeBlock>
|
|
</CodeGroup>
|
|
|
|
<Note title="LanceDB Enterprise">
|
|
New data added after creating the scalar index will still appear in search results if optimize is not used, but with increased latency due to a flat search on the unindexed portion. LanceDB Enterprise automates the optimize process, minimizing the impact on search speed.
|
|
</Note>
|
|
|
|
### 4. Run Indexed Searches
|
|
|
|
The following scan will be faster if the column `book_id` has a scalar index:
|
|
|
|
<CodeGroup>
|
|
<CodeBlock filename="Python" language="Python" icon="python">
|
|
{ScalarIndexFilter}
|
|
</CodeBlock>
|
|
</CodeGroup>
|
|
|
|
Scalar indexes can also speed up scans containing a vector search or full text search, and a prefilter:
|
|
|
|
<CodeGroup>
|
|
<CodeBlock filename="Python" language="Python" icon="python">
|
|
{ScalarIndexPrefilter}
|
|
</CodeBlock>
|
|
</CodeGroup>
|
|
|
|
## Indexing nested fields
|
|
|
|
Scalar indexes can target a scalar field inside a struct by passing its full dotted path. The path is preserved end to end: it's the value you pass to `create_scalar_index`, it's what `list_indices()` reports under `columns`, and it's the column reference you use in filter predicates.
|
|
|
|
```python
|
|
# Schema: pa.struct([pa.field("user_id", pa.int32())]) stored under the `metadata` column.
|
|
table.create_scalar_index("metadata.user_id", name="metadata_user_id_idx")
|
|
|
|
# The same dotted path works in WHERE clauses.
|
|
table.search().where("metadata.user_id = 42").limit(1).to_list()
|
|
```
|
|
|
|
<Note>
|
|
Nested paths follow Lance field-path semantics: dot-separate each struct field from root to leaf (for example, `metadata.author.name`). The same convention applies to FTS and vector indexes.
|
|
</Note>
|
|
|
|
## FM-Index for substring search
|
|
|
|
The `FM` index is a scalar index built over string or binary columns that
|
|
accelerates substring lookups expressed as `contains(col, 'needle')`. Unlike the
|
|
tokenized [FTS index](/indexing/fts-index), which matches whole words after
|
|
tokenization, the FM-Index matches arbitrary substrings of the raw bytes — so it
|
|
works well for URLs, file paths, identifiers, log lines, or any column where you
|
|
search for a fragment rather than a word.
|
|
|
|
Use the FM-Index when:
|
|
|
|
- Filters use `contains(col, 'needle')` (substring), not equality or word search.
|
|
- The column is `Utf8`, `LargeUtf8`, `Binary`, or `LargeBinary`.
|
|
- You want substring matches without paying for tokenization, language analysis,
|
|
or BM25 scoring.
|
|
|
|
Pick `FTS` instead when you need word-level relevance ranking, phrase queries,
|
|
or language-aware tokenization.
|
|
|
|
### Create an FM-Index
|
|
|
|
Build an FM-Index with the async `create_index` API by passing the `Fm` config in
|
|
Python or `Index.fm()` in TypeScript. In Rust, use `Index::Fm(FmIndexBuilder::default())`.
|
|
|
|
<CodeGroup>
|
|
```python Python icon="python"
|
|
from lancedb.index import Fm
|
|
|
|
await tbl.create_index("text", config=Fm())
|
|
```
|
|
|
|
```typescript TypeScript icon="square-js"
|
|
import * as lancedb from "@lancedb/lancedb";
|
|
import { Index } from "@lancedb/lancedb";
|
|
|
|
await tbl.createIndex("text", { config: Index.fm() });
|
|
```
|
|
|
|
```rust Rust icon="rust"
|
|
use lancedb::index::Index;
|
|
use lancedb::index::scalar::FmIndexBuilder;
|
|
|
|
tbl.create_index(&["text"], Index::Fm(FmIndexBuilder::default()))
|
|
.execute()
|
|
.await?;
|
|
```
|
|
</CodeGroup>
|
|
|
|
After the index is built, substring filters use it automatically:
|
|
|
|
```python
|
|
table.search().where("contains(text, 'needle')").limit(10).to_pandas()
|
|
```
|
|
|
|
`list_indices()` reports the index type as `"Fm"`.
|
|
|
|
## Index UUID Columns
|
|
|
|
LanceDB supports scalar indexes on UUID columns (stored as `FixedSizeBinary(16)`), enabling efficient lookups and filtering on UUID-based primary keys.
|
|
|
|
<Note>
|
|
**To use `FixedSizeBinary`, ensure you have:**
|
|
|
|
- Python SDK version `0.22.0` or later
|
|
- TypeScript SDK version `0.19.0` or later
|
|
</Note>
|
|
|
|
### 1. Define UUID Type
|
|
|
|
<CodeGroup>
|
|
<CodeBlock filename="Python" language="Python" icon="python">
|
|
{ScalarIndexUuidType}
|
|
</CodeBlock>
|
|
</CodeGroup>
|
|
|
|
### 2. Generate UUID Data
|
|
|
|
<CodeGroup>
|
|
<CodeBlock filename="Python" language="Python" icon="python">
|
|
{ScalarIndexUuidData}
|
|
</CodeBlock>
|
|
</CodeGroup>
|
|
|
|
### 3. Create Table with UUID Column
|
|
|
|
<CodeGroup>
|
|
<CodeBlock filename="Python" language="Python" icon="python">
|
|
{ScalarIndexUuidTable}
|
|
</CodeBlock>
|
|
</CodeGroup>
|
|
|
|
### 4. Create and Wait for the Index
|
|
|
|
<CodeGroup>
|
|
<CodeBlock filename="Python" language="Python" icon="python">
|
|
{ScalarIndexUuidWait}
|
|
</CodeBlock>
|
|
</CodeGroup>
|
|
|
|
### 5. Perform Operations with the UUID Index
|
|
|
|
<CodeGroup>
|
|
<CodeBlock filename="Python" language="Python" icon="python">
|
|
{ScalarIndexUuidUpsert}
|
|
</CodeBlock>
|
|
</CodeGroup>
|
|
|
|
## Index nested fields
|
|
|
|
You can build a scalar index on a field inside a struct column by passing the
|
|
canonical dot-separated path to `create_index`. This is useful when filters
|
|
target attributes nested under a `metadata`-style column, for example
|
|
`metadata.user_id` or `metadata.event.type`.
|
|
|
|
If a literal segment of the path itself contains a dot (for example a column
|
|
named `user.id` nested inside `metadata`), wrap that segment in backticks so
|
|
LanceDB can tell the dot apart from the path separator: `` metadata.`user.id` ``.
|
|
|
|
`list_indices()` echoes the same canonical path back, so the column you pass in
|
|
round-trips through index metadata regardless of nesting depth or escaping.
|
|
|
|
<CodeGroup>
|
|
<CodeBlock filename="Python" language="Python" icon="python">
|
|
{ScalarIndexNestedFields}
|
|
</CodeBlock>
|
|
</CodeGroup>
|
|
|
|
<Note>
|
|
Composite indexes that cover multiple columns aren't supported yet. Each
|
|
`create_index` call must target a single (possibly nested) field path.
|
|
</Note>
|