Skip to content

feat(format): add the MinHash LSH scalar index specification - #9071

Closed
zhangyue19921010 wants to merge 7 commits into
lance-format:mainfrom
zhangyue19921010:minhash-lsh-format
Closed

feat(format): add the MinHash LSH scalar index specification#9071
zhangyue19921010 wants to merge 7 commits into
lance-format:mainfrom
zhangyue19921010:minhash-lsh-format

Conversation

@zhangyue19921010

Copy link
Copy Markdown
Collaborator

Add MinHashLshIndexDetails, the persisted parameters of the MinHash LSH index (num_hashes, num_bands, shingle_size, the tokenizer recorded as the full text search index records it, and signature_version), and the format specification of its two files: the fixed-width signature table and the sorted band table with its page table, together with the signature procedure, the band key, reader navigation, multi-segment semantics and versioning.

The message references lance.table.InvertedIndexDetails from another proto package, so the build script maps that package to the module that already includes its generated code.

@github-actions github-actions Bot added A-index Vector index, linalg, tokenizer A-format On-disk format: protos and format spec docs format-change A change to the format spec, which requires a vote. Remove if minor (e.g. fixing typo). enhancement New feature or request labels Sep 9, 2026
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Important

Format specification vote

This PR modifies the Lance format specification, so it requires 3 binding +1 votes from PMC members (excluding the proposer) and a minimum 72-hour voting period, weekends excluded, before it can merge. Vote by approving this PR (+1) or requesting changes (−1, a veto). See the voting process.

Status: ❌ Blocked — 0 of 3 required approvals

Approvals (this commit) none (0/3)
Vetoes none
Voting period ends Mon 2026-09-14 06:51 UTC (Sun 23:51 PDT)

Updated automatically by the format-spec vote gate, which re-checks every 15 minutes — just voted? Re-check now (press Run workflow; leave the input blank to re-check every open format PR). A PMC member may apply the format-waived label to waive the vote for a trivial edit (typo, wording, formatting).

Add MinHashLshIndexDetails, the persisted parameters of the MinHash LSH
index (num_hashes, num_bands, shingle_size, the tokenizer recorded as the
full text search index records it, and signature_version), and the format
specification of its two files: the fixed-width signature table and the
sorted band table with its page table, together with the signature
procedure, the band key, reader navigation, multi-segment semantics and
versioning.

The message references lance.table.InvertedIndexDetails from another proto
package, so the build script maps that package to the module that already
includes its generated code.
lance-gatekeeper[bot]

This comment was marked as outdated.

@lance-gatekeeper lance-gatekeeper Bot added the K-changes Latest Gatekeeper recommendation requests changes. label Sep 9, 2026
Address the gate review of lance-format#9071: parameter ranges validated before any
allocation or read, the tokenizer subset the details can record, the exact
signature and band key procedure with known-answer vectors, the file schemas
with nullability and encoding settings, the schema metadata keys, the page
table layout and the checks made when a segment is opened.
@lance-gatekeeper lance-gatekeeper Bot removed the K-changes Latest Gatekeeper recommendation requests changes. label Sep 9, 2026
lance-gatekeeper[bot]

This comment was marked as outdated.

@lance-gatekeeper lance-gatekeeper Bot added the K-changes Latest Gatekeeper recommendation requests changes. label Sep 9, 2026
…rint tokenizer resources

Second gate round of lance-format#9071: executable PyArrow schemas for both files, the
serialized details repeated in both files and verified together with the
exact schema when a segment is opened, and a tokenizer_fingerprint field
that pins the dictionaries of resource-backed tokenizers, with the rule that
an implementation which does not compute it rejects those tokenizers.
@lance-gatekeeper lance-gatekeeper Bot removed the K-changes Latest Gatekeeper recommendation requests changes. label Sep 9, 2026
lance-gatekeeper[bot]

This comment was marked as outdated.

@lance-gatekeeper lance-gatekeeper Bot added the K-changes Latest Gatekeeper recommendation requests changes. label Sep 9, 2026
The fingerprint covers the tokenizer's directory, so the contract requires
every resource the configuration names to lie below it and forbids the
environment fallbacks, making the directory the complete resource closure.
@lance-gatekeeper lance-gatekeeper Bot removed the K-changes Latest Gatekeeper recommendation requests changes. label Sep 9, 2026
lance-gatekeeper[bot]

This comment was marked as outdated.

@lance-gatekeeper lance-gatekeeper Bot added the K-changes Latest Gatekeeper recommendation requests changes. label Sep 9, 2026
Drop tokenizer_fingerprint: a fingerprint of deployment files can only
detect drift, never let a reader reproduce signatures from the details, and
pinning it required specifying loader file-system semantics in the format.
Version 0 admits the tokenizers whose data ships with Lance, whose token
streams are part of signature_version, and rejects the dictionary-backed
jieba and lindera tokenizers; a later version may store their resources in
the index.
@lance-gatekeeper lance-gatekeeper Bot removed the K-changes Latest Gatekeeper recommendation requests changes. label Sep 9, 2026
zhangyue19921010 added a commit to zhangyue19921010/lance that referenced this pull request Sep 9, 2026
Follow the second revision of the format specification (lance-format#9071): both files
repeat the serialized MinHashLshIndexDetails in their schema metadata, and
opening a segment verifies the exact schema, the details and the layout
version of each file, so a signature file that does not belong to the bands
file is rejected instead of mis-ranking rows. The details gain the
tokenizer_fingerprint the specification defines for dictionary-backed
tokenizers; this version does not compute it, so it rejects those
tokenizers and any details carrying a fingerprint, as the specification
requires.
zhangyue19921010 added a commit to zhangyue19921010/lance that referenced this pull request Sep 9, 2026
…signature procedure

Follow the version-0 contract of lance-format#9071: drop tokenizer_fingerprint, reject
the dictionary-backed tokenizers because the details cannot identify their
resources, and group every tokenizer rule under one validation with one
reason. The details conversions form three symmetric pairs (message, Any in
the index metadata, hex in the index files).

@lance-gatekeeper lance-gatekeeper Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gate recommendation: request changes.

1 fixed / 3 remain. Restricting version 0 to built-in tokenizers removes deployment-resource drift, but the durable tokenizer contract still does not uniquely determine token streams across readers and releases.

A viable version 0 would use canonical tokenizer details and a small, fully specified tokenizer subset with conformance vectors for every admitted configuration. Broader Unicode, ICU, stemming, or stop-word support must freeze the exact algorithms and data it depends on. Once that contract is accepted, #9042 should rebase onto it and remove its overlapping schema change.


Version 0 therefore admits `simple`, `whitespace`, `raw`, `ngram`, `code`,
`icu` and `icu/split` as `base_tokenizer` (the ICU segmentation data is
compiled into Lance). The token stream these tokenizers produce for a given

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Version 0 still does not define the token streams it persists by reference. simple and code depend on Rust Unicode tables, icu on ICU4X data, and filters on Unicode normalization, frostem, and stop-word tables; repository history has already changed a stop-word stream without changing these persisted details. The only vector covers default simple ASCII text. An independent reader or later Lance release can therefore produce different signatures from equal details. Freeze the exact algorithms and data and add conformance vectors across every admitted tokenizer, filter, and configuration, or narrow version 0 to a fully specified table-free subset. This continues the tokenizer-identity finding.

The tokenizer is recorded as a `lance.table.InvertedIndexDetails`, the message
the Full-Text Search index persists, and is rebuilt from that message alone at
query time. The details must identify the tokenizer completely, so the
supported subset is what the message records about a tokenizer whose data

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The inner InvertedIndexDetails presence and default contract is ambiguous. A present empty message satisfies the outer presence requirement, but the existing FTS decoder expands it to simple, English, length 40, with stemming and stop-word removal enabled; protobuf scalar defaults instead expose false, zero, or absent values, while the MinHash default disables stemming and stop words. Readers can therefore reject or tokenize the same persisted bytes differently. Require canonical explicit shaping values, including base_tokenizer, and reject empty or partial legacy encodings, or define exact absence semantics.

Reproducer

Executed on this head in a temporary Cargo binary depending on rust/lance-index; cargo run completed successfully:

use lance_index::{pbold::InvertedIndexDetails, scalar::InvertedIndexParams};

fn main() {
    let params =
        InvertedIndexParams::try_from(&InvertedIndexDetails::default()).unwrap();
    assert_eq!(params.base_tokenizer, "simple");
    assert_eq!(params.max_token_length, Some(40));
    assert!(params.stem);
    assert!(params.remove_stop_words);
}

`max_token_length = 40`, `lower_case = true`, `ascii_folding = true`,
`stem = false` and `remove_stop_words = false`.

Version 0 therefore admits `simple`, `whitespace`, `raw`, `ngram`, `code`,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Admitting raw makes the empty-input rule contradictory. The current Lance RawTokenizer emits one token containing the entire input for both "" and " ", while Signature Generation says these inputs have no token or signature and must not be indexed. Readers can therefore hash and index them or skip them. Define an explicit preprocessing rule before tokenization, define no-signature behavior solely from emitted token count and correct the examples, or remove raw from version 0.

Reproducer

Executed on this head in a temporary Cargo binary depending on rust/lance-tokenizer; cargo run exited successfully:

use lance_tokenizer::{RawTokenizer, TokenStream, Tokenizer};

fn main() {
    let mut tokenizer = RawTokenizer::default();
    for text in ["", "   "] {
        let mut stream = tokenizer.token_stream(text);
        assert!(stream.advance());
        assert_eq!(stream.token().text, text);
        assert!(!stream.advance());
    }
}

@lance-gatekeeper lance-gatekeeper Bot added the K-changes Latest Gatekeeper recommendation requests changes. label Sep 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-format On-disk format: protos and format spec docs A-index Vector index, linalg, tokenizer enhancement New feature or request format-change A change to the format spec, which requires a vote. Remove if minor (e.g. fixing typo). K-changes Latest Gatekeeper recommendation requests changes.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant