mirror of
https://github.com/lancedb/lancedb.git
synced 2025-12-23 05:19:58 +00:00
Compare commits
56 Commits
python-v0.
...
python-v0.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8f42b5874e | ||
|
|
274f19f560 | ||
|
|
fbcbc75b5b | ||
|
|
008f389bd0 | ||
|
|
91af6518d9 | ||
|
|
af6819762c | ||
|
|
7acece493d | ||
|
|
20e017fedc | ||
|
|
74e578b3c8 | ||
|
|
d92d9eb3d2 | ||
|
|
b6cdce7bc9 | ||
|
|
316b406265 | ||
|
|
8825c7c1dd | ||
|
|
81c85ff702 | ||
|
|
570f2154d5 | ||
|
|
0525c055fc | ||
|
|
38d11291da | ||
|
|
258e682574 | ||
|
|
d7afa600b8 | ||
|
|
5c7303ab2e | ||
|
|
5895ef4039 | ||
|
|
0528cd858a | ||
|
|
6582f43422 | ||
|
|
5c7f63388d | ||
|
|
d0bc671cac | ||
|
|
d37e17593d | ||
|
|
cb726d370e | ||
|
|
23ee132546 | ||
|
|
7fa090d330 | ||
|
|
07bc1c5397 | ||
|
|
d7a9dbb9fc | ||
|
|
00487afc7d | ||
|
|
1902d65aad | ||
|
|
c4fbb65b8e | ||
|
|
875ed7ae6f | ||
|
|
95a46a57ba | ||
|
|
51561e31a0 | ||
|
|
7b19120578 | ||
|
|
745c34a6a9 | ||
|
|
db8fa2454d | ||
|
|
a67a7b4b42 | ||
|
|
496846e532 | ||
|
|
dadcfebf8e | ||
|
|
67033dbd7f | ||
|
|
05a85cfc2a | ||
|
|
40c5d3d72b | ||
|
|
198f0f80c6 | ||
|
|
e3f2fd3892 | ||
|
|
f401ccc599 | ||
|
|
81b59139f8 | ||
|
|
1026781ab6 | ||
|
|
9c699b8cd9 | ||
|
|
34bec59bc3 | ||
|
|
a5fbbf0d66 | ||
|
|
b42721167b | ||
|
|
543dec9ff0 |
@@ -1,5 +1,5 @@
|
|||||||
[tool.bumpversion]
|
[tool.bumpversion]
|
||||||
current_version = "0.19.1-beta.3"
|
current_version = "0.20.0-beta.2"
|
||||||
parse = """(?x)
|
parse = """(?x)
|
||||||
(?P<major>0|[1-9]\\d*)\\.
|
(?P<major>0|[1-9]\\d*)\\.
|
||||||
(?P<minor>0|[1-9]\\d*)\\.
|
(?P<minor>0|[1-9]\\d*)\\.
|
||||||
|
|||||||
7
.github/workflows/java.yml
vendored
7
.github/workflows/java.yml
vendored
@@ -35,6 +35,9 @@ jobs:
|
|||||||
- uses: Swatinem/rust-cache@v2
|
- uses: Swatinem/rust-cache@v2
|
||||||
with:
|
with:
|
||||||
workspaces: java/core/lancedb-jni
|
workspaces: java/core/lancedb-jni
|
||||||
|
- uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||||
|
with:
|
||||||
|
components: rustfmt
|
||||||
- name: Run cargo fmt
|
- name: Run cargo fmt
|
||||||
run: cargo fmt --check
|
run: cargo fmt --check
|
||||||
working-directory: ./java/core/lancedb-jni
|
working-directory: ./java/core/lancedb-jni
|
||||||
@@ -68,6 +71,9 @@ jobs:
|
|||||||
- uses: Swatinem/rust-cache@v2
|
- uses: Swatinem/rust-cache@v2
|
||||||
with:
|
with:
|
||||||
workspaces: java/core/lancedb-jni
|
workspaces: java/core/lancedb-jni
|
||||||
|
- uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||||
|
with:
|
||||||
|
components: rustfmt
|
||||||
- name: Run cargo fmt
|
- name: Run cargo fmt
|
||||||
run: cargo fmt --check
|
run: cargo fmt --check
|
||||||
working-directory: ./java/core/lancedb-jni
|
working-directory: ./java/core/lancedb-jni
|
||||||
@@ -110,4 +116,3 @@ jobs:
|
|||||||
-Djdk.reflect.useDirectMethodHandle=false \
|
-Djdk.reflect.useDirectMethodHandle=false \
|
||||||
-Dio.netty.tryReflectionSetAccessible=true"
|
-Dio.netty.tryReflectionSetAccessible=true"
|
||||||
JAVA_HOME=$JAVA_17 mvn clean test
|
JAVA_HOME=$JAVA_17 mvn clean test
|
||||||
|
|
||||||
|
|||||||
9
.github/workflows/make-release-commit.yml
vendored
9
.github/workflows/make-release-commit.yml
vendored
@@ -84,6 +84,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
pip install bump-my-version PyGithub packaging
|
pip install bump-my-version PyGithub packaging
|
||||||
bash ci/bump_version.sh ${{ inputs.type }} ${{ inputs.bump-minor }} v $COMMIT_BEFORE_BUMP
|
bash ci/bump_version.sh ${{ inputs.type }} ${{ inputs.bump-minor }} v $COMMIT_BEFORE_BUMP
|
||||||
|
bash ci/update_lockfiles.sh --amend
|
||||||
- name: Push new version tag
|
- name: Push new version tag
|
||||||
if: ${{ !inputs.dry_run }}
|
if: ${{ !inputs.dry_run }}
|
||||||
uses: ad-m/github-push-action@master
|
uses: ad-m/github-push-action@master
|
||||||
@@ -92,11 +93,3 @@ jobs:
|
|||||||
github_token: ${{ secrets.LANCEDB_RELEASE_TOKEN }}
|
github_token: ${{ secrets.LANCEDB_RELEASE_TOKEN }}
|
||||||
branch: ${{ github.ref }}
|
branch: ${{ github.ref }}
|
||||||
tags: true
|
tags: true
|
||||||
- uses: ./.github/workflows/update_package_lock
|
|
||||||
if: ${{ !inputs.dry_run && inputs.other }}
|
|
||||||
with:
|
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- uses: ./.github/workflows/update_package_lock_nodejs
|
|
||||||
if: ${{ !inputs.dry_run && inputs.other }}
|
|
||||||
with:
|
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|||||||
5
.github/workflows/nodejs.yml
vendored
5
.github/workflows/nodejs.yml
vendored
@@ -47,6 +47,9 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt install -y protobuf-compiler libssl-dev
|
sudo apt install -y protobuf-compiler libssl-dev
|
||||||
|
- uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||||
|
with:
|
||||||
|
components: rustfmt, clippy
|
||||||
- name: Lint
|
- name: Lint
|
||||||
run: |
|
run: |
|
||||||
cargo fmt --all -- --check
|
cargo fmt --all -- --check
|
||||||
@@ -113,7 +116,7 @@ jobs:
|
|||||||
set -e
|
set -e
|
||||||
npm ci
|
npm ci
|
||||||
npm run docs
|
npm run docs
|
||||||
if ! git diff --exit-code; then
|
if ! git diff --exit-code -- . ':(exclude)Cargo.lock'; then
|
||||||
echo "Docs need to be updated"
|
echo "Docs need to be updated"
|
||||||
echo "Run 'npm run docs', fix any warnings, and commit the changes."
|
echo "Run 'npm run docs', fix any warnings, and commit the changes."
|
||||||
exit 1
|
exit 1
|
||||||
|
|||||||
24
.github/workflows/npm-publish.yml
vendored
24
.github/workflows/npm-publish.yml
vendored
@@ -505,6 +505,8 @@ jobs:
|
|||||||
name: vectordb NPM Publish
|
name: vectordb NPM Publish
|
||||||
needs: [node, node-macos, node-linux-gnu, node-windows]
|
needs: [node, node-macos, node-linux-gnu, node-windows]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
# Only runs on tags that matches the make-release action
|
# Only runs on tags that matches the make-release action
|
||||||
if: startsWith(github.ref, 'refs/tags/v')
|
if: startsWith(github.ref, 'refs/tags/v')
|
||||||
steps:
|
steps:
|
||||||
@@ -537,6 +539,10 @@ jobs:
|
|||||||
# We need to deprecate the old package to avoid confusion.
|
# We need to deprecate the old package to avoid confusion.
|
||||||
# Each time we publish a new version, it gets undeprecated.
|
# Each time we publish a new version, it gets undeprecated.
|
||||||
run: npm deprecate vectordb "Use @lancedb/lancedb instead."
|
run: npm deprecate vectordb "Use @lancedb/lancedb instead."
|
||||||
|
- name: Update package-lock.json
|
||||||
|
run: bash ci/update_lockfiles.sh
|
||||||
|
- name: Push new commit
|
||||||
|
uses: ad-m/github-push-action@master
|
||||||
- name: Notify Slack Action
|
- name: Notify Slack Action
|
||||||
uses: ravsamhq/notify-slack-action@2.3.0
|
uses: ravsamhq/notify-slack-action@2.3.0
|
||||||
if: ${{ always() }}
|
if: ${{ always() }}
|
||||||
@@ -546,21 +552,3 @@ jobs:
|
|||||||
notification_title: "{workflow} is failing"
|
notification_title: "{workflow} is failing"
|
||||||
env:
|
env:
|
||||||
SLACK_WEBHOOK_URL: ${{ secrets.ACTION_MONITORING_SLACK }}
|
SLACK_WEBHOOK_URL: ${{ secrets.ACTION_MONITORING_SLACK }}
|
||||||
|
|
||||||
update-package-lock:
|
|
||||||
if: startsWith(github.ref, 'refs/tags/v')
|
|
||||||
needs: [release]
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
ref: main
|
|
||||||
token: ${{ secrets.LANCEDB_RELEASE_TOKEN }}
|
|
||||||
fetch-depth: 0
|
|
||||||
lfs: true
|
|
||||||
- uses: ./.github/workflows/update_package_lock
|
|
||||||
with:
|
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|||||||
4
.github/workflows/run_tests/action.yml
vendored
4
.github/workflows/run_tests/action.yml
vendored
@@ -24,8 +24,8 @@ runs:
|
|||||||
- name: pytest (with integration)
|
- name: pytest (with integration)
|
||||||
shell: bash
|
shell: bash
|
||||||
if: ${{ inputs.integration == 'true' }}
|
if: ${{ inputs.integration == 'true' }}
|
||||||
run: pytest -m "not slow" -x -v --durations=30 python/python/tests
|
run: pytest -m "not slow" -vv --durations=30 python/python/tests
|
||||||
- name: pytest (no integration tests)
|
- name: pytest (no integration tests)
|
||||||
shell: bash
|
shell: bash
|
||||||
if: ${{ inputs.integration != 'true' }}
|
if: ${{ inputs.integration != 'true' }}
|
||||||
run: pytest -m "not slow and not s3_test" -x -v --durations=30 python/python/tests
|
run: pytest -m "not slow and not s3_test" -vv --durations=30 python/python/tests
|
||||||
|
|||||||
7
.github/workflows/rust.yml
vendored
7
.github/workflows/rust.yml
vendored
@@ -40,6 +40,9 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
lfs: true
|
lfs: true
|
||||||
|
- uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||||
|
with:
|
||||||
|
components: rustfmt, clippy
|
||||||
- uses: Swatinem/rust-cache@v2
|
- uses: Swatinem/rust-cache@v2
|
||||||
with:
|
with:
|
||||||
workspaces: rust
|
workspaces: rust
|
||||||
@@ -160,8 +163,8 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
target:
|
target:
|
||||||
- x86_64-pc-windows-msvc
|
- x86_64-pc-windows-msvc
|
||||||
- aarch64-pc-windows-msvc
|
- aarch64-pc-windows-msvc
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
working-directory: rust/lancedb
|
working-directory: rust/lancedb
|
||||||
|
|||||||
33
.github/workflows/update_package_lock/action.yml
vendored
33
.github/workflows/update_package_lock/action.yml
vendored
@@ -1,33 +0,0 @@
|
|||||||
name: update_package_lock
|
|
||||||
description: "Update node's package.lock"
|
|
||||||
|
|
||||||
inputs:
|
|
||||||
github_token:
|
|
||||||
required: true
|
|
||||||
description: "github token for the repo"
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: "composite"
|
|
||||||
steps:
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 20
|
|
||||||
- name: Set git configs
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
git config user.name 'Lance Release'
|
|
||||||
git config user.email 'lance-dev@lancedb.com'
|
|
||||||
- name: Update package-lock.json file
|
|
||||||
working-directory: ./node
|
|
||||||
run: |
|
|
||||||
npm install
|
|
||||||
git add package-lock.json
|
|
||||||
git commit -m "Updating package-lock.json"
|
|
||||||
shell: bash
|
|
||||||
- name: Push changes
|
|
||||||
if: ${{ inputs.dry_run }} == "false"
|
|
||||||
uses: ad-m/github-push-action@master
|
|
||||||
with:
|
|
||||||
github_token: ${{ inputs.github_token }}
|
|
||||||
branch: main
|
|
||||||
tags: true
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
name: update_package_lock_nodejs
|
|
||||||
description: "Update nodejs's package.lock"
|
|
||||||
|
|
||||||
inputs:
|
|
||||||
github_token:
|
|
||||||
required: true
|
|
||||||
description: "github token for the repo"
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: "composite"
|
|
||||||
steps:
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 20
|
|
||||||
- name: Set git configs
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
git config user.name 'Lance Release'
|
|
||||||
git config user.email 'lance-dev@lancedb.com'
|
|
||||||
- name: Update package-lock.json file
|
|
||||||
working-directory: ./nodejs
|
|
||||||
run: |
|
|
||||||
npm install
|
|
||||||
git add package-lock.json
|
|
||||||
git commit -m "Updating package-lock.json"
|
|
||||||
shell: bash
|
|
||||||
- name: Push changes
|
|
||||||
if: ${{ inputs.dry_run }} == "false"
|
|
||||||
uses: ad-m/github-push-action@master
|
|
||||||
with:
|
|
||||||
github_token: ${{ inputs.github_token }}
|
|
||||||
branch: main
|
|
||||||
tags: true
|
|
||||||
1417
Cargo.lock
generated
1417
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
53
Cargo.toml
53
Cargo.toml
@@ -21,32 +21,32 @@ categories = ["database-implementations"]
|
|||||||
rust-version = "1.78.0"
|
rust-version = "1.78.0"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
lance = { "version" = "=0.27.0", "features" = ["dynamodb"], tag = "v0.27.0-beta.5", git="https://github.com/lancedb/lance.git" }
|
lance = { "version" = "=0.29.0", "features" = ["dynamodb"] }
|
||||||
lance-io = { version = "=0.27.0", tag = "v0.27.0-beta.5", git="https://github.com/lancedb/lance.git" }
|
lance-io = "=0.29.0"
|
||||||
lance-index = { version = "=0.27.0", tag = "v0.27.0-beta.5", git="https://github.com/lancedb/lance.git" }
|
lance-index = "=0.29.0"
|
||||||
lance-linalg = { version = "=0.27.0", tag = "v0.27.0-beta.5", git="https://github.com/lancedb/lance.git" }
|
lance-linalg = "=0.29.0"
|
||||||
lance-table = { version = "=0.27.0", tag = "v0.27.0-beta.5", git="https://github.com/lancedb/lance.git" }
|
lance-table = "=0.29.0"
|
||||||
lance-testing = { version = "=0.27.0", tag = "v0.27.0-beta.5", git="https://github.com/lancedb/lance.git" }
|
lance-testing = "=0.29.0"
|
||||||
lance-datafusion = { version = "=0.27.0", tag = "v0.27.0-beta.5", git="https://github.com/lancedb/lance.git" }
|
lance-datafusion = "=0.29.0"
|
||||||
lance-encoding = { version = "=0.27.0", tag = "v0.27.0-beta.5", git="https://github.com/lancedb/lance.git" }
|
lance-encoding = "=0.29.0"
|
||||||
# Note that this one does not include pyarrow
|
# Note that this one does not include pyarrow
|
||||||
arrow = { version = "54.1", optional = false }
|
arrow = { version = "55.1", optional = false }
|
||||||
arrow-array = "54.1"
|
arrow-array = "55.1"
|
||||||
arrow-data = "54.1"
|
arrow-data = "55.1"
|
||||||
arrow-ipc = "54.1"
|
arrow-ipc = "55.1"
|
||||||
arrow-ord = "54.1"
|
arrow-ord = "55.1"
|
||||||
arrow-schema = "54.1"
|
arrow-schema = "55.1"
|
||||||
arrow-arith = "54.1"
|
arrow-arith = "55.1"
|
||||||
arrow-cast = "54.1"
|
arrow-cast = "55.1"
|
||||||
async-trait = "0"
|
async-trait = "0"
|
||||||
datafusion = { version = "46.0", default-features = false }
|
datafusion = { version = "47.0", default-features = false }
|
||||||
datafusion-catalog = "46.0"
|
datafusion-catalog = "47.0"
|
||||||
datafusion-common = { version = "46.0", default-features = false }
|
datafusion-common = { version = "47.0", default-features = false }
|
||||||
datafusion-execution = "46.0"
|
datafusion-execution = "47.0"
|
||||||
datafusion-expr = "46.0"
|
datafusion-expr = "47.0"
|
||||||
datafusion-physical-plan = "46.0"
|
datafusion-physical-plan = "47.0"
|
||||||
env_logger = "0.11"
|
env_logger = "0.11"
|
||||||
half = { "version" = "=2.4.1", default-features = false, features = [
|
half = { "version" = "=2.5.0", default-features = false, features = [
|
||||||
"num-traits",
|
"num-traits",
|
||||||
] }
|
] }
|
||||||
futures = "0"
|
futures = "0"
|
||||||
@@ -57,19 +57,16 @@ pin-project = "1.0.7"
|
|||||||
snafu = "0.8"
|
snafu = "0.8"
|
||||||
url = "2"
|
url = "2"
|
||||||
num-traits = "0.2"
|
num-traits = "0.2"
|
||||||
rand = "0.8"
|
rand = "0.9"
|
||||||
regex = "1.10"
|
regex = "1.10"
|
||||||
lazy_static = "1"
|
lazy_static = "1"
|
||||||
semver = "1.0.25"
|
semver = "1.0.25"
|
||||||
|
|
||||||
# Temporary pins to work around downstream issues
|
# Temporary pins to work around downstream issues
|
||||||
# https://github.com/apache/arrow-rs/commit/2fddf85afcd20110ce783ed5b4cdeb82293da30b
|
# https://github.com/apache/arrow-rs/commit/2fddf85afcd20110ce783ed5b4cdeb82293da30b
|
||||||
chrono = "=0.4.39"
|
chrono = "=0.4.41"
|
||||||
# https://github.com/RustCrypto/formats/issues/1684
|
# https://github.com/RustCrypto/formats/issues/1684
|
||||||
base64ct = "=1.6.0"
|
base64ct = "=1.6.0"
|
||||||
|
|
||||||
# Workaround for: https://github.com/eira-fransham/crunchy/issues/13
|
# Workaround for: https://github.com/eira-fransham/crunchy/issues/13
|
||||||
crunchy = "=0.2.2"
|
crunchy = "=0.2.2"
|
||||||
|
|
||||||
# Workaround for: https://github.com/Lokathor/bytemuck/issues/306
|
# Workaround for: https://github.com/Lokathor/bytemuck/issues/306
|
||||||
bytemuck_derive = ">=1.8.1, <1.9.0"
|
bytemuck_derive = ">=1.8.1, <1.9.0"
|
||||||
|
|||||||
129
README.md
129
README.md
@@ -1,94 +1,97 @@
|
|||||||
<a href="https://cloud.lancedb.com" target="_blank">
|
<a href="https://cloud.lancedb.com" target="_blank">
|
||||||
<img src="https://github.com/user-attachments/assets/92dad0a2-2a37-4ce1-b783-0d1b4f30a00c" alt="LanceDB Cloud Public Beta" width="100%" style="max-width: 100%;">
|
<img src="https://github.com/user-attachments/assets/92dad0a2-2a37-4ce1-b783-0d1b4f30a00c" alt="LanceDB Cloud Public Beta" width="100%" style="max-width: 100%;">
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<p align="center">
|
|
||||||
|
|
||||||
<picture>
|
[](https://lancedb.com)
|
||||||
<source media="(prefers-color-scheme: dark)" srcset="https://github.com/user-attachments/assets/ac270358-333e-4bea-a132-acefaa94040e">
|
[](https://lancedb.com/)
|
||||||
<source media="(prefers-color-scheme: light)" srcset="https://github.com/user-attachments/assets/b864d814-0d29-4784-8fd9-807297c758c0">
|
[](https://blog.lancedb.com/)
|
||||||
<img alt="LanceDB Logo" src="https://github.com/user-attachments/assets/b864d814-0d29-4784-8fd9-807297c758c0" width=300>
|
[](https://discord.gg/zMM32dvNtd)
|
||||||
</picture>
|
[](https://twitter.com/lancedb)
|
||||||
|
[](https://www.linkedin.com/company/lancedb/)
|
||||||
|
|
||||||
**Search More, Manage Less**
|
|
||||||
|
|
||||||
<a href='https://github.com/lancedb/vectordb-recipes/tree/main' target="_blank"><img alt='LanceDB' src='https://img.shields.io/badge/VectorDB_Recipes-100000?style=for-the-badge&logo=LanceDB&logoColor=white&labelColor=645cfb&color=645cfb'/></a>
|
<img src="docs/src/assets/lancedb.png" alt="LanceDB" width="50%">
|
||||||
<a href='https://lancedb.github.io/lancedb/' target="_blank"><img alt='lancdb' src='https://img.shields.io/badge/DOCS-100000?style=for-the-badge&logo=lancdb&logoColor=white&labelColor=645cfb&color=645cfb'/></a>
|
|
||||||
[](https://blog.lancedb.com/)
|
|
||||||
[](https://discord.gg/zMM32dvNtd)
|
|
||||||
[](https://twitter.com/lancedb)
|
|
||||||
[](https://gurubase.io/g/lancedb)
|
|
||||||
|
|
||||||
</p>
|
# **The Multimodal AI Lakehouse**
|
||||||
|
|
||||||
<img max-width="750px" alt="LanceDB Multimodal Search" src="https://github.com/lancedb/lancedb/assets/917119/09c5afc5-7816-4687-bae4-f2ca194426ec">
|
[**How to Install** ](#how-to-install) ✦ [**Detailed Documentation**](https://lancedb.github.io/lancedb/) ✦ [**Tutorials and Recipes**](https://github.com/lancedb/vectordb-recipes/tree/main) ✦ [**Contributors**](#contributors)
|
||||||
|
|
||||||
|
**The ultimate multimodal data platform for AI/ML applications.**
|
||||||
|
|
||||||
|
LanceDB is designed for fast, scalable, and production-ready vector search. It is built on top of the Lance columnar format. You can store, index, and search over petabytes of multimodal data and vectors with ease.
|
||||||
|
LanceDB is a central location where developers can build, train and analyze their AI workloads.
|
||||||
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr />
|
<br>
|
||||||
|
|
||||||
LanceDB is an open-source database for vector-search built with persistent storage, which greatly simplifies retrieval, filtering and management of embeddings.
|
## **Demo: Multimodal Search by Keyword, Vector or with SQL**
|
||||||
|
<img max-width="750px" alt="LanceDB Multimodal Search" src="https://github.com/lancedb/lancedb/assets/917119/09c5afc5-7816-4687-bae4-f2ca194426ec">
|
||||||
|
|
||||||
The key features of LanceDB include:
|
## **Star LanceDB to get updates!**
|
||||||
|
|
||||||
* Production-scale vector search with no servers to manage.
|
<details>
|
||||||
|
<summary>⭐ Click here ⭐ to see how fast we're growing!</summary>
|
||||||
|
<picture>
|
||||||
|
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=lancedb/lancedb&theme=dark&type=Date">
|
||||||
|
<img width="100%" src="https://api.star-history.com/svg?repos=lancedb/lancedb&theme=dark&type=Date">
|
||||||
|
</picture>
|
||||||
|
</details>
|
||||||
|
|
||||||
* Store, query and filter vectors, metadata and multi-modal data (text, images, videos, point clouds, and more).
|
## **Key Features**:
|
||||||
|
|
||||||
* Support for vector similarity search, full-text search and SQL.
|
- **Fast Vector Search**: Search billions of vectors in milliseconds with state-of-the-art indexing.
|
||||||
|
- **Comprehensive Search**: Support for vector similarity search, full-text search and SQL.
|
||||||
|
- **Multimodal Support**: Store, query and filter vectors, metadata and multimodal data (text, images, videos, point clouds, and more).
|
||||||
|
- **Advanced Features**: Zero-copy, automatic versioning, manage versions of your data without needing extra infrastructure. GPU support in building vector index.
|
||||||
|
|
||||||
* Native Python and Javascript/Typescript support.
|
### **Products**:
|
||||||
|
- **Open Source & Local**: 100% open source, runs locally or in your cloud. No vendor lock-in.
|
||||||
|
- **Cloud and Enterprise**: Production-scale vector search with no servers to manage. Complete data sovereignty and security.
|
||||||
|
|
||||||
* Zero-copy, automatic versioning, manage versions of your data without needing extra infrastructure.
|
### **Ecosystem**:
|
||||||
|
- **Columnar Storage**: Built on the Lance columnar format for efficient storage and analytics.
|
||||||
|
- **Seamless Integration**: Python, Node.js, Rust, and REST APIs for easy integration. Native Python and Javascript/Typescript support.
|
||||||
|
- **Rich Ecosystem**: Integrations with [**LangChain** 🦜️🔗](https://python.langchain.com/docs/integrations/vectorstores/lancedb/), [**LlamaIndex** 🦙](https://gpt-index.readthedocs.io/en/latest/examples/vector_stores/LanceDBIndexDemo.html), Apache-Arrow, Pandas, Polars, DuckDB and more on the way.
|
||||||
|
|
||||||
* GPU support in building vector index(*).
|
## **How to Install**:
|
||||||
|
|
||||||
* Ecosystem integrations with [LangChain 🦜️🔗](https://python.langchain.com/docs/integrations/vectorstores/lancedb/), [LlamaIndex 🦙](https://gpt-index.readthedocs.io/en/latest/examples/vector_stores/LanceDBIndexDemo.html), Apache-Arrow, Pandas, Polars, DuckDB and more on the way.
|
Follow the [Quickstart](https://lancedb.github.io/lancedb/basic/) doc to set up LanceDB locally.
|
||||||
|
|
||||||
LanceDB's core is written in Rust 🦀 and is built using <a href="https://github.com/lancedb/lance">Lance</a>, an open-source columnar format designed for performant ML workloads.
|
**API & SDK:** We also support Python, Typescript and Rust SDKs
|
||||||
|
|
||||||
## Quick Start
|
| Interface | Documentation |
|
||||||
|
|-----------|---------------|
|
||||||
|
| Python SDK | https://lancedb.github.io/lancedb/python/python/ |
|
||||||
|
| Typescript SDK | https://lancedb.github.io/lancedb/js/globals/ |
|
||||||
|
| Rust SDK | https://docs.rs/lancedb/latest/lancedb/index.html |
|
||||||
|
| REST API | https://docs.lancedb.com/api-reference/introduction |
|
||||||
|
|
||||||
**Javascript**
|
## **Join Us and Contribute**
|
||||||
```shell
|
|
||||||
npm install @lancedb/lancedb
|
|
||||||
```
|
|
||||||
|
|
||||||
```javascript
|
We welcome contributions from everyone! Whether you're a developer, researcher, or just someone who wants to help out.
|
||||||
import * as lancedb from "@lancedb/lancedb";
|
|
||||||
|
|
||||||
const db = await lancedb.connect("data/sample-lancedb");
|
If you have any suggestions or feature requests, please feel free to open an issue on GitHub or discuss it on our [**Discord**](https://discord.gg/G5DcmnZWKB) server.
|
||||||
const table = await db.createTable("vectors", [
|
|
||||||
{ id: 1, vector: [0.1, 0.2], item: "foo", price: 10 },
|
[**Check out the GitHub Issues**](https://github.com/lancedb/lancedb/issues) if you would like to work on the features that are planned for the future. If you have any suggestions or feature requests, please feel free to open an issue on GitHub.
|
||||||
{ id: 2, vector: [1.1, 1.2], item: "bar", price: 50 },
|
|
||||||
], {mode: 'overwrite'});
|
## **Contributors**
|
||||||
|
|
||||||
|
<a href="https://github.com/lancedb/lancedb/graphs/contributors">
|
||||||
|
<img src="https://contrib.rocks/image?repo=lancedb/lancedb" />
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
const query = table.vectorSearch([0.1, 0.3]).limit(2);
|
## **Stay in Touch With Us**
|
||||||
const results = await query.toArray();
|
<div align="center">
|
||||||
|
|
||||||
// You can also search for rows by specific criteria without involving a vector search.
|
</br>
|
||||||
const rowsByCriteria = await table.query().where("price >= 10").toArray();
|
|
||||||
```
|
|
||||||
|
|
||||||
**Python**
|
[](https://lancedb.com/)
|
||||||
```shell
|
[](https://blog.lancedb.com/)
|
||||||
pip install lancedb
|
[](https://discord.gg/zMM32dvNtd)
|
||||||
```
|
[](https://twitter.com/lancedb)
|
||||||
|
[](https://www.linkedin.com/company/lancedb/)
|
||||||
|
|
||||||
```python
|
</div>
|
||||||
import lancedb
|
|
||||||
|
|
||||||
uri = "data/sample-lancedb"
|
|
||||||
db = lancedb.connect(uri)
|
|
||||||
table = db.create_table("my_table",
|
|
||||||
data=[{"vector": [3.1, 4.1], "item": "foo", "price": 10.0},
|
|
||||||
{"vector": [5.9, 26.5], "item": "bar", "price": 20.0}])
|
|
||||||
result = table.search([100, 100]).limit(2).to_pandas()
|
|
||||||
```
|
|
||||||
|
|
||||||
## Blogs, Tutorials & Videos
|
|
||||||
* 📈 <a href="https://blog.lancedb.com/benchmarking-random-access-in-lance/">2000x better performance with Lance over Parquet</a>
|
|
||||||
* 🤖 <a href="https://github.com/lancedb/vectordb-recipes/tree/main/examples/Youtube-Search-QA-Bot">Build a question and answer bot with LanceDB</a>
|
|
||||||
|
|||||||
174
ci/set_lance_version.py
Normal file
174
ci/set_lance_version.py
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
import argparse
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
def run_command(command: str) -> str:
|
||||||
|
"""
|
||||||
|
Run a shell command and return stdout as a string.
|
||||||
|
If exit code is not 0, raise an exception with the stderr output.
|
||||||
|
"""
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
result = subprocess.run(command, shell=True, capture_output=True, text=True)
|
||||||
|
if result.returncode != 0:
|
||||||
|
raise Exception(f"Command failed with error: {result.stderr.strip()}")
|
||||||
|
return result.stdout.strip()
|
||||||
|
|
||||||
|
|
||||||
|
def get_latest_stable_version() -> str:
|
||||||
|
version_line = run_command("cargo info lance | grep '^version:'")
|
||||||
|
version = version_line.split(" ")[1].strip()
|
||||||
|
return version
|
||||||
|
|
||||||
|
|
||||||
|
def get_latest_preview_version() -> str:
|
||||||
|
lance_tags = run_command(
|
||||||
|
"git ls-remote --tags https://github.com/lancedb/lance.git | grep 'refs/tags/v[0-9beta.-]\\+$'"
|
||||||
|
).splitlines()
|
||||||
|
lance_tags = (
|
||||||
|
tag.split("refs/tags/")[1]
|
||||||
|
for tag in lance_tags
|
||||||
|
if "refs/tags/" in tag and "beta" in tag
|
||||||
|
)
|
||||||
|
from packaging.version import Version
|
||||||
|
|
||||||
|
latest = max(
|
||||||
|
(tag[1:] for tag in lance_tags if tag.startswith("v")), key=lambda t: Version(t)
|
||||||
|
)
|
||||||
|
return str(latest)
|
||||||
|
|
||||||
|
|
||||||
|
def extract_features(line: str) -> list:
|
||||||
|
"""
|
||||||
|
Extracts the features from a line in Cargo.toml.
|
||||||
|
Example: 'lance = { "version" = "=0.29.0", "features" = ["dynamodb"] }'
|
||||||
|
Returns: ['dynamodb']
|
||||||
|
"""
|
||||||
|
import re
|
||||||
|
|
||||||
|
match = re.search(r'"features"\s*=\s*\[(.*?)\]', line)
|
||||||
|
if match:
|
||||||
|
features_str = match.group(1)
|
||||||
|
return [f.strip('"') for f in features_str.split(",")]
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def update_cargo_toml(line_updater):
|
||||||
|
"""
|
||||||
|
Updates the Cargo.toml file by applying the line_updater function to each line.
|
||||||
|
The line_updater function should take a line as input and return the updated line.
|
||||||
|
"""
|
||||||
|
with open("Cargo.toml", "r") as f:
|
||||||
|
lines = f.readlines()
|
||||||
|
|
||||||
|
new_lines = []
|
||||||
|
for line in lines:
|
||||||
|
if line.startswith("lance"):
|
||||||
|
# Update the line using the provided function
|
||||||
|
new_lines.append(line_updater(line))
|
||||||
|
else:
|
||||||
|
# Keep the line unchanged
|
||||||
|
new_lines.append(line)
|
||||||
|
|
||||||
|
with open("Cargo.toml", "w") as f:
|
||||||
|
f.writelines(new_lines)
|
||||||
|
|
||||||
|
|
||||||
|
def set_stable_version(version: str):
|
||||||
|
"""
|
||||||
|
Sets lines to
|
||||||
|
lance = { "version" = "=0.29.0", "features" = ["dynamodb"] }
|
||||||
|
lance-io = "=0.29.0"
|
||||||
|
...
|
||||||
|
"""
|
||||||
|
|
||||||
|
def line_updater(line: str) -> str:
|
||||||
|
package_name = line.split("=", maxsplit=1)[0].strip()
|
||||||
|
features = extract_features(line)
|
||||||
|
if features:
|
||||||
|
return f'{package_name} = {{ "version" = "={version}", "features" = {json.dumps(features)} }}\n'
|
||||||
|
else:
|
||||||
|
return f'{package_name} = "={version}"\n'
|
||||||
|
|
||||||
|
update_cargo_toml(line_updater)
|
||||||
|
|
||||||
|
|
||||||
|
def set_preview_version(version: str):
|
||||||
|
"""
|
||||||
|
Sets lines to
|
||||||
|
lance = { "version" = "=0.29.0", "features" = ["dynamodb"], tag = "v0.29.0-beta.2", git="https://github.com/lancedb/lance.git" }
|
||||||
|
lance-io = { version = "=0.29.0", tag = "v0.29.0-beta.2", git="https://github.com/lancedb/lance.git" }
|
||||||
|
...
|
||||||
|
"""
|
||||||
|
|
||||||
|
def line_updater(line: str) -> str:
|
||||||
|
package_name = line.split("=", maxsplit=1)[0].strip()
|
||||||
|
features = extract_features(line)
|
||||||
|
base_version = version.split("-")[0] # Get the base version without beta suffix
|
||||||
|
if features:
|
||||||
|
return f'{package_name} = {{ "version" = "={base_version}", "features" = {json.dumps(features)}, "tag" = "v{version}", "git" = "https://github.com/lancedb/lance.git" }}\n'
|
||||||
|
else:
|
||||||
|
return f'{package_name} = {{ "version" = "={base_version}", "tag" = "v{version}", "git" = "https://github.com/lancedb/lance.git" }}\n'
|
||||||
|
|
||||||
|
update_cargo_toml(line_updater)
|
||||||
|
|
||||||
|
|
||||||
|
def set_local_version():
|
||||||
|
"""
|
||||||
|
Sets lines to
|
||||||
|
lance = { path = "../lance/rust/lance", features = ["dynamodb"] }
|
||||||
|
lance-io = { path = "../lance/rust/lance-io" }
|
||||||
|
...
|
||||||
|
"""
|
||||||
|
|
||||||
|
def line_updater(line: str) -> str:
|
||||||
|
package_name = line.split("=", maxsplit=1)[0].strip()
|
||||||
|
features = extract_features(line)
|
||||||
|
if features:
|
||||||
|
return f'{package_name} = {{ "path" = "../lance/rust/{package_name}", "features" = {json.dumps(features)} }}\n'
|
||||||
|
else:
|
||||||
|
return f'{package_name} = {{ "path" = "../lance/rust/{package_name}" }}\n'
|
||||||
|
|
||||||
|
update_cargo_toml(line_updater)
|
||||||
|
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description="Set the version of the Lance package.")
|
||||||
|
parser.add_argument(
|
||||||
|
"version",
|
||||||
|
type=str,
|
||||||
|
help="The version to set for the Lance package. Use 'stable' for the latest stable version, 'preview' for latest preview version, or a specific version number (e.g., '0.1.0'). You can also specify 'local' to use a local path.",
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.version == "stable":
|
||||||
|
latest_stable_version = get_latest_stable_version()
|
||||||
|
print(
|
||||||
|
f"Found latest stable version: \033[1mv{latest_stable_version}\033[0m",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
|
set_stable_version(latest_stable_version)
|
||||||
|
elif args.version == "preview":
|
||||||
|
latest_preview_version = get_latest_preview_version()
|
||||||
|
print(
|
||||||
|
f"Found latest preview version: \033[1mv{latest_preview_version}\033[0m",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
|
set_preview_version(latest_preview_version)
|
||||||
|
elif args.version == "local":
|
||||||
|
set_local_version()
|
||||||
|
else:
|
||||||
|
# Parse the version number.
|
||||||
|
version = args.version
|
||||||
|
# Ignore initial v if present.
|
||||||
|
if version.startswith("v"):
|
||||||
|
version = version[1:]
|
||||||
|
|
||||||
|
if "beta" in version:
|
||||||
|
set_preview_version(version)
|
||||||
|
else:
|
||||||
|
set_stable_version(version)
|
||||||
|
|
||||||
|
print("Updating lockfiles...", file=sys.stderr, end="")
|
||||||
|
run_command("cargo metadata > /dev/null")
|
||||||
|
print(" done.", file=sys.stderr)
|
||||||
30
ci/update_lockfiles.sh
Executable file
30
ci/update_lockfiles.sh
Executable file
@@ -0,0 +1,30 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
AMEND=false
|
||||||
|
|
||||||
|
for arg in "$@"; do
|
||||||
|
if [[ "$arg" == "--amend" ]]; then
|
||||||
|
AMEND=true
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# This updates the lockfile without building
|
||||||
|
cargo metadata --quiet > /dev/null
|
||||||
|
|
||||||
|
pushd nodejs || exit 1
|
||||||
|
npm install --package-lock-only --silent
|
||||||
|
popd
|
||||||
|
pushd node || exit 1
|
||||||
|
npm install --package-lock-only --silent
|
||||||
|
popd
|
||||||
|
|
||||||
|
if git diff --quiet --exit-code; then
|
||||||
|
echo "No lockfile changes to commit; skipping amend."
|
||||||
|
elif $AMEND; then
|
||||||
|
git add Cargo.lock nodejs/package-lock.json node/package-lock.json
|
||||||
|
git commit --amend --no-edit
|
||||||
|
else
|
||||||
|
git add Cargo.lock nodejs/package-lock.json node/package-lock.json
|
||||||
|
git commit -m "Update lockfiles"
|
||||||
|
fi
|
||||||
@@ -193,6 +193,7 @@ nav:
|
|||||||
- Pandas and PyArrow: python/pandas_and_pyarrow.md
|
- Pandas and PyArrow: python/pandas_and_pyarrow.md
|
||||||
- Polars: python/polars_arrow.md
|
- Polars: python/polars_arrow.md
|
||||||
- DuckDB: python/duckdb.md
|
- DuckDB: python/duckdb.md
|
||||||
|
- Datafusion: python/datafusion.md
|
||||||
- LangChain:
|
- LangChain:
|
||||||
- LangChain 🔗: integrations/langchain.md
|
- LangChain 🔗: integrations/langchain.md
|
||||||
- LangChain demo: notebooks/langchain_demo.ipynb
|
- LangChain demo: notebooks/langchain_demo.ipynb
|
||||||
@@ -205,6 +206,7 @@ nav:
|
|||||||
- PromptTools: integrations/prompttools.md
|
- PromptTools: integrations/prompttools.md
|
||||||
- dlt: integrations/dlt.md
|
- dlt: integrations/dlt.md
|
||||||
- phidata: integrations/phidata.md
|
- phidata: integrations/phidata.md
|
||||||
|
- Genkit: integrations/genkit.md
|
||||||
- 🎯 Examples:
|
- 🎯 Examples:
|
||||||
- Overview: examples/index.md
|
- Overview: examples/index.md
|
||||||
- 🐍 Python:
|
- 🐍 Python:
|
||||||
@@ -247,6 +249,7 @@ nav:
|
|||||||
- Data management: concepts/data_management.md
|
- Data management: concepts/data_management.md
|
||||||
- Guides:
|
- Guides:
|
||||||
- Working with tables: guides/tables.md
|
- Working with tables: guides/tables.md
|
||||||
|
- Working with SQL: guides/sql_querying.md
|
||||||
- Building an ANN index: ann_indexes.md
|
- Building an ANN index: ann_indexes.md
|
||||||
- Vector Search: search.md
|
- Vector Search: search.md
|
||||||
- Full-text search (native): fts.md
|
- Full-text search (native): fts.md
|
||||||
@@ -323,6 +326,7 @@ nav:
|
|||||||
- Pandas and PyArrow: python/pandas_and_pyarrow.md
|
- Pandas and PyArrow: python/pandas_and_pyarrow.md
|
||||||
- Polars: python/polars_arrow.md
|
- Polars: python/polars_arrow.md
|
||||||
- DuckDB: python/duckdb.md
|
- DuckDB: python/duckdb.md
|
||||||
|
- Datafusion: python/datafusion.md
|
||||||
- LangChain 🦜️🔗↗: integrations/langchain.md
|
- LangChain 🦜️🔗↗: integrations/langchain.md
|
||||||
- LangChain.js 🦜️🔗↗: https://js.langchain.com/docs/integrations/vectorstores/lancedb
|
- LangChain.js 🦜️🔗↗: https://js.langchain.com/docs/integrations/vectorstores/lancedb
|
||||||
- LlamaIndex 🦙↗: integrations/llamaIndex.md
|
- LlamaIndex 🦙↗: integrations/llamaIndex.md
|
||||||
@@ -331,6 +335,7 @@ nav:
|
|||||||
- PromptTools: integrations/prompttools.md
|
- PromptTools: integrations/prompttools.md
|
||||||
- dlt: integrations/dlt.md
|
- dlt: integrations/dlt.md
|
||||||
- phidata: integrations/phidata.md
|
- phidata: integrations/phidata.md
|
||||||
|
- Genkit: integrations/genkit.md
|
||||||
- Examples:
|
- Examples:
|
||||||
- examples/index.md
|
- examples/index.md
|
||||||
- 🐍 Python:
|
- 🐍 Python:
|
||||||
|
|||||||
5
docs/overrides/partials/main.html
Normal file
5
docs/overrides/partials/main.html
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block announce %}
|
||||||
|
📚 Starting June 1st, 2025, please use <a href="https://lancedb.github.io/documentation" target="_blank" rel="noopener noreferrer">lancedb.github.io/documentation</a> for the latest docs.
|
||||||
|
{% endblock %}
|
||||||
@@ -291,7 +291,7 @@ Product quantization can lead to approximately `16 * sizeof(float32) / 1 = 64` t
|
|||||||
|
|
||||||
`num_partitions` is used to decide how many partitions the first level `IVF` index uses.
|
`num_partitions` is used to decide how many partitions the first level `IVF` index uses.
|
||||||
Higher number of partitions could lead to more efficient I/O during queries and better accuracy, but it takes much more time to train.
|
Higher number of partitions could lead to more efficient I/O during queries and better accuracy, but it takes much more time to train.
|
||||||
On `SIFT-1M` dataset, our benchmark shows that keeping each partition 1K-4K rows lead to a good latency / recall.
|
On `SIFT-1M` dataset, our benchmark shows that keeping each partition 4K-8K rows lead to a good latency / recall.
|
||||||
|
|
||||||
`num_sub_vectors` specifies how many Product Quantization (PQ) short codes to generate on each vector. The number should be a factor of the vector dimension. Because
|
`num_sub_vectors` specifies how many Product Quantization (PQ) short codes to generate on each vector. The number should be a factor of the vector dimension. Because
|
||||||
PQ is a lossy compression of the original vector, a higher `num_sub_vectors` usually results in
|
PQ is a lossy compression of the original vector, a higher `num_sub_vectors` usually results in
|
||||||
|
|||||||
BIN
docs/src/assets/hero-header.png
Normal file
BIN
docs/src/assets/hero-header.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 MiB |
BIN
docs/src/assets/lancedb.png
Normal file
BIN
docs/src/assets/lancedb.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
66
docs/src/guides/sql_querying.md
Normal file
66
docs/src/guides/sql_querying.md
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
You can use DuckDB and Apache Datafusion to query your LanceDB tables using SQL.
|
||||||
|
This guide will show how to query Lance tables them using both.
|
||||||
|
|
||||||
|
We will re-use the dataset [created previously](./pandas_and_pyarrow.md):
|
||||||
|
|
||||||
|
```python
|
||||||
|
import lancedb
|
||||||
|
|
||||||
|
db = lancedb.connect("data/sample-lancedb")
|
||||||
|
data = [
|
||||||
|
{"vector": [3.1, 4.1], "item": "foo", "price": 10.0},
|
||||||
|
{"vector": [5.9, 26.5], "item": "bar", "price": 20.0}
|
||||||
|
]
|
||||||
|
table = db.create_table("pd_table", data=data)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Querying a LanceDB Table with DuckDb
|
||||||
|
|
||||||
|
The `to_lance` method converts the LanceDB table to a `LanceDataset`, which is accessible to DuckDB through the Arrow compatibility layer.
|
||||||
|
To query the resulting Lance dataset in DuckDB, all you need to do is reference the dataset by the same name in your SQL query.
|
||||||
|
|
||||||
|
```python
|
||||||
|
import duckdb
|
||||||
|
|
||||||
|
arrow_table = table.to_lance()
|
||||||
|
|
||||||
|
duckdb.query("SELECT * FROM arrow_table")
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────┬─────────┬────────┐
|
||||||
|
│ vector │ item │ price │
|
||||||
|
│ float[] │ varchar │ double │
|
||||||
|
├─────────────┼─────────┼────────┤
|
||||||
|
│ [3.1, 4.1] │ foo │ 10.0 │
|
||||||
|
│ [5.9, 26.5] │ bar │ 20.0 │
|
||||||
|
└─────────────┴─────────┴────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## Querying a LanceDB Table with Apache Datafusion
|
||||||
|
|
||||||
|
Have the required imports before doing any querying.
|
||||||
|
|
||||||
|
=== "Python"
|
||||||
|
```python
|
||||||
|
--8<-- "python/python/tests/docs/test_guide_tables.py:import-lancedb"
|
||||||
|
--8<-- "python/python/tests/docs/test_guide_tables.py:import-session-context"
|
||||||
|
--8<-- "python/python/tests/docs/test_guide_tables.py:import-ffi-dataset"
|
||||||
|
```
|
||||||
|
|
||||||
|
Register the table created with the Datafusion session context.
|
||||||
|
|
||||||
|
=== "Python"
|
||||||
|
```python
|
||||||
|
--8<-- "python/python/tests/docs/test_guide_tables.py:lance_sql_basic"
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────┬─────────┬────────┐
|
||||||
|
│ vector │ item │ price │
|
||||||
|
│ float[] │ varchar │ double │
|
||||||
|
├─────────────┼─────────┼────────┤
|
||||||
|
│ [3.1, 4.1] │ foo │ 10.0 │
|
||||||
|
│ [5.9, 26.5] │ bar │ 20.0 │
|
||||||
|
└─────────────┴─────────┴────────┘
|
||||||
|
```
|
||||||
@@ -765,7 +765,7 @@ This can be used to update zero to all rows depending on how many rows match the
|
|||||||
];
|
];
|
||||||
const tbl = await db.createTable("my_table", data)
|
const tbl = await db.createTable("my_table", data)
|
||||||
|
|
||||||
await tbl.update({
|
await tbl.update({
|
||||||
values: { vector: [10, 10] },
|
values: { vector: [10, 10] },
|
||||||
where: "x = 2"
|
where: "x = 2"
|
||||||
});
|
});
|
||||||
@@ -787,9 +787,9 @@ This can be used to update zero to all rows depending on how many rows match the
|
|||||||
];
|
];
|
||||||
const tbl = await db.createTable("my_table", data)
|
const tbl = await db.createTable("my_table", data)
|
||||||
|
|
||||||
await tbl.update({
|
await tbl.update({
|
||||||
where: "x = 2",
|
where: "x = 2",
|
||||||
values: { vector: [10, 10] }
|
values: { vector: [10, 10] }
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
183
docs/src/integrations/genkit.md
Normal file
183
docs/src/integrations/genkit.md
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
### genkitx-lancedb
|
||||||
|
This is a lancedb plugin for genkit framework. It allows you to use LanceDB for ingesting and rereiving data using genkit framework.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Installation
|
||||||
|
```bash
|
||||||
|
pnpm install genkitx-lancedb
|
||||||
|
```
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
Adding LanceDB plugin to your genkit instance.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { lancedbIndexerRef, lancedb, lancedbRetrieverRef, WriteMode } from 'genkitx-lancedb';
|
||||||
|
import { textEmbedding004, vertexAI } from '@genkit-ai/vertexai';
|
||||||
|
import { gemini } from '@genkit-ai/vertexai';
|
||||||
|
import { z, genkit } from 'genkit';
|
||||||
|
import { Document } from 'genkit/retriever';
|
||||||
|
import { chunk } from 'llm-chunk';
|
||||||
|
import { readFile } from 'fs/promises';
|
||||||
|
import path from 'path';
|
||||||
|
import pdf from 'pdf-parse/lib/pdf-parse';
|
||||||
|
|
||||||
|
const ai = genkit({
|
||||||
|
plugins: [
|
||||||
|
// vertexAI provides the textEmbedding004 embedder
|
||||||
|
vertexAI(),
|
||||||
|
|
||||||
|
// the local vector store requires an embedder to translate from text to vector
|
||||||
|
lancedb([
|
||||||
|
{
|
||||||
|
dbUri: '.db', // optional lancedb uri, default to .db
|
||||||
|
tableName: 'table', // optional table name, default to table
|
||||||
|
embedder: textEmbedding004,
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
You can run this app with the following command:
|
||||||
|
```bash
|
||||||
|
genkit start -- tsx --watch src/index.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
This'll add LanceDB as a retriever and indexer to the genkit instance. You can see it in the GUI view
|
||||||
|
<img width="1710" alt="Screenshot 2025-05-11 at 7 21 05 PM" src="https://github.com/user-attachments/assets/e752f7f4-785b-4797-a11e-72ab06a531b7" />
|
||||||
|
|
||||||
|
**Testing retrieval on a sample table**
|
||||||
|
Let's see the raw retrieval results
|
||||||
|
|
||||||
|
<img width="1710" alt="Screenshot 2025-05-11 at 7 21 05 PM" src="https://github.com/user-attachments/assets/b8d356ed-8421-4790-8fc0-d6af563b9657" />
|
||||||
|
On running this query, you'll 5 results fetched from the lancedb table, where each result looks something like this:
|
||||||
|
<img width="1417" alt="Screenshot 2025-05-11 at 7 21 18 PM" src="https://github.com/user-attachments/assets/77429525-36e2-4da6-a694-e58c1cf9eb83" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Creating a custom RAG flow
|
||||||
|
|
||||||
|
Now that we've seen how you can use LanceDB for in a genkit pipeline, let's refine the flow and create a RAG. A RAG flow will consist of an index and a retreiver with its outputs postprocessed an fed into an LLM for final response
|
||||||
|
|
||||||
|
### Creating custom indexer flows
|
||||||
|
You can also create custom indexer flows, utilizing more options and features provided by LanceDB.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
export const menuPdfIndexer = lancedbIndexerRef({
|
||||||
|
// Using all defaults, for dbUri, tableName, and embedder, etc
|
||||||
|
});
|
||||||
|
|
||||||
|
const chunkingConfig = {
|
||||||
|
minLength: 1000,
|
||||||
|
maxLength: 2000,
|
||||||
|
splitter: 'sentence',
|
||||||
|
overlap: 100,
|
||||||
|
delimiters: '',
|
||||||
|
} as any;
|
||||||
|
|
||||||
|
|
||||||
|
async function extractTextFromPdf(filePath: string) {
|
||||||
|
const pdfFile = path.resolve(filePath);
|
||||||
|
const dataBuffer = await readFile(pdfFile);
|
||||||
|
const data = await pdf(dataBuffer);
|
||||||
|
return data.text;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const indexMenu = ai.defineFlow(
|
||||||
|
{
|
||||||
|
name: 'indexMenu',
|
||||||
|
inputSchema: z.string().describe('PDF file path'),
|
||||||
|
outputSchema: z.void(),
|
||||||
|
},
|
||||||
|
async (filePath: string) => {
|
||||||
|
filePath = path.resolve(filePath);
|
||||||
|
|
||||||
|
// Read the pdf.
|
||||||
|
const pdfTxt = await ai.run('extract-text', () =>
|
||||||
|
extractTextFromPdf(filePath)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Divide the pdf text into segments.
|
||||||
|
const chunks = await ai.run('chunk-it', async () =>
|
||||||
|
chunk(pdfTxt, chunkingConfig)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Convert chunks of text into documents to store in the index.
|
||||||
|
const documents = chunks.map((text) => {
|
||||||
|
return Document.fromText(text, { filePath });
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add documents to the index.
|
||||||
|
await ai.index({
|
||||||
|
indexer: menuPdfIndexer,
|
||||||
|
documents,
|
||||||
|
options: {
|
||||||
|
writeMode: WriteMode.Overwrite,
|
||||||
|
} as any
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
<img width="1316" alt="Screenshot 2025-05-11 at 8 35 56 PM" src="https://github.com/user-attachments/assets/e2a20ce4-d1d0-4fa2-9a84-f2cc26e3a29f" />
|
||||||
|
|
||||||
|
In your console, you can see the logs
|
||||||
|
|
||||||
|
<img width="511" alt="Screenshot 2025-05-11 at 7 19 14 PM" src="https://github.com/user-attachments/assets/243f26c5-ed38-40b6-b661-002f40f0423a" />
|
||||||
|
|
||||||
|
### Creating custom retriever flows
|
||||||
|
You can also create custom retriever flows, utilizing more options and features provided by LanceDB.
|
||||||
|
```ts
|
||||||
|
export const menuRetriever = lancedbRetrieverRef({
|
||||||
|
tableName: "table", // Use the same table name as the indexer.
|
||||||
|
displayName: "Menu", // Use a custom display name.
|
||||||
|
|
||||||
|
export const menuQAFlow = ai.defineFlow(
|
||||||
|
{ name: "Menu", inputSchema: z.string(), outputSchema: z.string() },
|
||||||
|
async (input: string) => {
|
||||||
|
// retrieve relevant documents
|
||||||
|
const docs = await ai.retrieve({
|
||||||
|
retriever: menuRetriever,
|
||||||
|
query: input,
|
||||||
|
options: {
|
||||||
|
k: 3,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const extractedContent = docs.map(doc => {
|
||||||
|
if (doc.content && Array.isArray(doc.content) && doc.content.length > 0) {
|
||||||
|
if (doc.content[0].media && doc.content[0].media.url) {
|
||||||
|
return doc.content[0].media.url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "No content found";
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("Extracted content:", extractedContent);
|
||||||
|
|
||||||
|
const { text } = await ai.generate({
|
||||||
|
model: gemini('gemini-2.0-flash'),
|
||||||
|
prompt: `
|
||||||
|
You are acting as a helpful AI assistant that can answer
|
||||||
|
questions about the food available on the menu at Genkit Grub Pub.
|
||||||
|
|
||||||
|
Use only the context provided to answer the question.
|
||||||
|
If you don't know, do not make up an answer.
|
||||||
|
Do not add or change items on the menu.
|
||||||
|
|
||||||
|
Context:
|
||||||
|
${extractedContent.join('\n\n')}
|
||||||
|
|
||||||
|
Question: ${input}`,
|
||||||
|
docs,
|
||||||
|
});
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
```
|
||||||
|
Now using our retrieval flow, we can ask question about the ingsted PDF
|
||||||
|
<img width="1306" alt="Screenshot 2025-05-11 at 7 18 45 PM" src="https://github.com/user-attachments/assets/86c66b13-7c12-4d5f-9d81-ae36bfb1c346" />
|
||||||
|
|
||||||
53
docs/src/python/datafusion.md
Normal file
53
docs/src/python/datafusion.md
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
# Apache Datafusion
|
||||||
|
|
||||||
|
In Python, LanceDB tables can also be queried with [Apache Datafusion](https://datafusion.apache.org/), an extensible query engine written in Rust that uses Apache Arrow as its in-memory format. This means you can write complex SQL queries to analyze your data in LanceDB.
|
||||||
|
|
||||||
|
This integration is done via [Datafusion FFI](https://docs.rs/datafusion-ffi/latest/datafusion_ffi/), which provides a native integration between LanceDB and Datafusion.
|
||||||
|
The Datafusion FFI allows to pass down column selections and basic filters to LanceDB, reducing the amount of scanned data when executing your query. Additionally, the integration allows streaming data from LanceDB tables which allows to do aggregation larger-than-memory.
|
||||||
|
|
||||||
|
We can demonstrate this by first installing `datafusion` and `lancedb`.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
pip install datafusion lancedb
|
||||||
|
```
|
||||||
|
|
||||||
|
We will re-use the dataset [created previously](./pandas_and_pyarrow.md):
|
||||||
|
|
||||||
|
```python
|
||||||
|
import lancedb
|
||||||
|
|
||||||
|
from datafusion import SessionContext
|
||||||
|
from lance import FFILanceTableProvider
|
||||||
|
|
||||||
|
db = lancedb.connect("data/sample-lancedb")
|
||||||
|
data = [
|
||||||
|
{"vector": [3.1, 4.1], "item": "foo", "price": 10.0},
|
||||||
|
{"vector": [5.9, 26.5], "item": "bar", "price": 20.0}
|
||||||
|
]
|
||||||
|
lance_table = db.create_table("lance_table", data)
|
||||||
|
|
||||||
|
ctx = SessionContext()
|
||||||
|
|
||||||
|
ffi_lance_table = FFILanceTableProvider(
|
||||||
|
lance_table.to_lance(), with_row_id=True, with_row_addr=True
|
||||||
|
)
|
||||||
|
ctx.register_table_provider("ffi_lance_table", ffi_lance_table)
|
||||||
|
```
|
||||||
|
|
||||||
|
The `to_lance` method converts the LanceDB table to a `LanceDataset`, which is accessible to Datafusion through the Datafusion FFI integration layer.
|
||||||
|
To query the resulting Lance dataset in Datafusion, you first need to register the dataset with Datafusion and then just reference it by the same name in your SQL query.
|
||||||
|
|
||||||
|
```python
|
||||||
|
ctx.table("ffi_lance_table")
|
||||||
|
ctx.sql("SELECT * FROM ffi_lance_table")
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────┬─────────┬────────┬─────────────────┬─────────────────┐
|
||||||
|
│ vector │ item │ price │ _rowid │ _rowaddr │
|
||||||
|
│ float[] │ varchar │ double │ bigint unsigned │ bigint unsigned │
|
||||||
|
├─────────────┼─────────┼────────┼─────────────────┼─────────────────┤
|
||||||
|
│ [3.1, 4.1] │ foo │ 10.0 │ 0 │ 0 │
|
||||||
|
│ [5.9, 26.5] │ bar │ 20.0 │ 1 │ 1 │
|
||||||
|
└─────────────┴─────────┴────────┴─────────────────┴─────────────────┘
|
||||||
|
```
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.lancedb</groupId>
|
<groupId>com.lancedb</groupId>
|
||||||
<artifactId>lancedb-parent</artifactId>
|
<artifactId>lancedb-parent</artifactId>
|
||||||
<version>0.19.1-beta.3</version>
|
<version>0.20.0-beta.2</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<groupId>com.lancedb</groupId>
|
<groupId>com.lancedb</groupId>
|
||||||
<artifactId>lancedb-parent</artifactId>
|
<artifactId>lancedb-parent</artifactId>
|
||||||
<version>0.19.1-beta.3</version>
|
<version>0.20.0-beta.2</version>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
<name>LanceDB Parent</name>
|
<name>LanceDB Parent</name>
|
||||||
|
|||||||
49
node/package-lock.json
generated
49
node/package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "vectordb",
|
"name": "vectordb",
|
||||||
"version": "0.19.1-beta.3",
|
"version": "0.20.0-beta.2",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "vectordb",
|
"name": "vectordb",
|
||||||
"version": "0.19.1-beta.3",
|
"version": "0.20.0-beta.2",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64",
|
"x64",
|
||||||
"arm64"
|
"arm64"
|
||||||
@@ -52,11 +52,11 @@
|
|||||||
"uuid": "^9.0.0"
|
"uuid": "^9.0.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@lancedb/vectordb-darwin-arm64": "0.19.1-beta.3",
|
"@lancedb/vectordb-darwin-arm64": "0.20.0-beta.2",
|
||||||
"@lancedb/vectordb-darwin-x64": "0.19.1-beta.3",
|
"@lancedb/vectordb-darwin-x64": "0.20.0-beta.2",
|
||||||
"@lancedb/vectordb-linux-arm64-gnu": "0.19.1-beta.3",
|
"@lancedb/vectordb-linux-arm64-gnu": "0.20.0-beta.2",
|
||||||
"@lancedb/vectordb-linux-x64-gnu": "0.19.1-beta.3",
|
"@lancedb/vectordb-linux-x64-gnu": "0.20.0-beta.2",
|
||||||
"@lancedb/vectordb-win32-x64-msvc": "0.19.1-beta.3"
|
"@lancedb/vectordb-win32-x64-msvc": "0.20.0-beta.2"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@apache-arrow/ts": "^14.0.2",
|
"@apache-arrow/ts": "^14.0.2",
|
||||||
@@ -327,65 +327,60 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@lancedb/vectordb-darwin-arm64": {
|
"node_modules/@lancedb/vectordb-darwin-arm64": {
|
||||||
"version": "0.19.1-beta.3",
|
"version": "0.20.0-beta.2",
|
||||||
"resolved": "https://registry.npmjs.org/@lancedb/vectordb-darwin-arm64/-/vectordb-darwin-arm64-0.19.1-beta.3.tgz",
|
"resolved": "https://registry.npmjs.org/@lancedb/vectordb-darwin-arm64/-/vectordb-darwin-arm64-0.20.0-beta.2.tgz",
|
||||||
"integrity": "sha512-TglTNkvgxxHHhh8YbEwj5t9XuInNVUNeFN34Zyk+7ab/rDdMASiKv6ZvDkwacVm7aXeBbLw39/6+IegStJfFCg==",
|
"integrity": "sha512-H9PmJ/5KSvstVzR8Q7T22+eHRjJZ2ef3aA3gdFxXvoMi3xQ0MGIxz23HuKHGTRT4tfl1nNnpOPb2W7Na8etK9w==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"license": "Apache-2.0",
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@lancedb/vectordb-darwin-x64": {
|
"node_modules/@lancedb/vectordb-darwin-x64": {
|
||||||
"version": "0.19.1-beta.3",
|
"version": "0.20.0-beta.2",
|
||||||
"resolved": "https://registry.npmjs.org/@lancedb/vectordb-darwin-x64/-/vectordb-darwin-x64-0.19.1-beta.3.tgz",
|
"resolved": "https://registry.npmjs.org/@lancedb/vectordb-darwin-x64/-/vectordb-darwin-x64-0.20.0-beta.2.tgz",
|
||||||
"integrity": "sha512-mwBbOVgeUT3xyegzga0gTBJ+DXI3dP1zPKcOQRQDRJk+GkfHk1CblGXT3h/YL18NWfR1FGMe9s59PNJR6r6l8A==",
|
"integrity": "sha512-9AQkv4tIys+vg0cplZtSE48o61jd7EnmuMkUht+vLORL5/HAma84eAoU9lXHT7zAtPAQmL+98Bfvcsx7fJ6mVw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"license": "Apache-2.0",
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@lancedb/vectordb-linux-arm64-gnu": {
|
"node_modules/@lancedb/vectordb-linux-arm64-gnu": {
|
||||||
"version": "0.19.1-beta.3",
|
"version": "0.20.0-beta.2",
|
||||||
"resolved": "https://registry.npmjs.org/@lancedb/vectordb-linux-arm64-gnu/-/vectordb-linux-arm64-gnu-0.19.1-beta.3.tgz",
|
"resolved": "https://registry.npmjs.org/@lancedb/vectordb-linux-arm64-gnu/-/vectordb-linux-arm64-gnu-0.20.0-beta.2.tgz",
|
||||||
"integrity": "sha512-amihspQ5ThSKRJsPpeAte/edWDGAN5ZjdqhtX8AUuuOmoJ5EekfsgXZc+fyFNwl6RzGT7PKqpL7SQzOdLKMijQ==",
|
"integrity": "sha512-eQWoJz2ePml7NyEInTBeakWx56+5c6r2p3F+iHC5tsLuznn6eFX90koXJunRxH1WXHDN48ECUlEmKypgfEmn4w==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"license": "Apache-2.0",
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@lancedb/vectordb-linux-x64-gnu": {
|
"node_modules/@lancedb/vectordb-linux-x64-gnu": {
|
||||||
"version": "0.19.1-beta.3",
|
"version": "0.20.0-beta.2",
|
||||||
"resolved": "https://registry.npmjs.org/@lancedb/vectordb-linux-x64-gnu/-/vectordb-linux-x64-gnu-0.19.1-beta.3.tgz",
|
"resolved": "https://registry.npmjs.org/@lancedb/vectordb-linux-x64-gnu/-/vectordb-linux-x64-gnu-0.20.0-beta.2.tgz",
|
||||||
"integrity": "sha512-mZzOETBii+UUu7D2TOohhukXNjjOfldbNADRB20FF2a3hYzrVteiFudCQRYtbVunpHE0qvNRTkyuRqM7DwOygw==",
|
"integrity": "sha512-/+84U+Dt07m8Jk0b8h+SvOzlrynITPP3SDBOlB+OonwmGSxirXhc8gkfNZctgXOJYKMyRIRSsMHP/QNjOp2ajA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"license": "Apache-2.0",
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@lancedb/vectordb-win32-x64-msvc": {
|
"node_modules/@lancedb/vectordb-win32-x64-msvc": {
|
||||||
"version": "0.19.1-beta.3",
|
"version": "0.20.0-beta.2",
|
||||||
"resolved": "https://registry.npmjs.org/@lancedb/vectordb-win32-x64-msvc/-/vectordb-win32-x64-msvc-0.19.1-beta.3.tgz",
|
"resolved": "https://registry.npmjs.org/@lancedb/vectordb-win32-x64-msvc/-/vectordb-win32-x64-msvc-0.20.0-beta.2.tgz",
|
||||||
"integrity": "sha512-LHsKFtJZRRZ4MVa6uSeWqPJ9vfw0atmp6bvVDByxgouVN4CwdlnAxOu69YJtwDPxnfg8Pn+eQ5txIFvhFtCAnA==",
|
"integrity": "sha512-bgdunAPnknBh/5oO+vr6RXMr6wb3hHugNPXcIidxYMQvgFa8uhaAKtgYkAKuoyUReOYo8DGtVkZxNUUpZbF7/A==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"license": "Apache-2.0",
|
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "vectordb",
|
"name": "vectordb",
|
||||||
"version": "0.19.1-beta.3",
|
"version": "0.20.0-beta.2",
|
||||||
"description": " Serverless, low-latency vector database for AI applications",
|
"description": " Serverless, low-latency vector database for AI applications",
|
||||||
"private": false,
|
"private": false,
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
@@ -89,10 +89,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@lancedb/vectordb-darwin-x64": "0.19.1-beta.3",
|
"@lancedb/vectordb-darwin-x64": "0.20.0-beta.2",
|
||||||
"@lancedb/vectordb-darwin-arm64": "0.19.1-beta.3",
|
"@lancedb/vectordb-darwin-arm64": "0.20.0-beta.2",
|
||||||
"@lancedb/vectordb-linux-x64-gnu": "0.19.1-beta.3",
|
"@lancedb/vectordb-linux-x64-gnu": "0.20.0-beta.2",
|
||||||
"@lancedb/vectordb-linux-arm64-gnu": "0.19.1-beta.3",
|
"@lancedb/vectordb-linux-arm64-gnu": "0.20.0-beta.2",
|
||||||
"@lancedb/vectordb-win32-x64-msvc": "0.19.1-beta.3"
|
"@lancedb/vectordb-win32-x64-msvc": "0.20.0-beta.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "lancedb-nodejs"
|
name = "lancedb-nodejs"
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
version = "0.19.1-beta.3"
|
version = "0.20.0-beta.2"
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
description.workspace = true
|
description.workspace = true
|
||||||
repository.workspace = true
|
repository.workspace = true
|
||||||
@@ -30,6 +30,7 @@ log.workspace = true
|
|||||||
|
|
||||||
# Workaround for build failure until we can fix it.
|
# Workaround for build failure until we can fix it.
|
||||||
aws-lc-sys = "=0.28.0"
|
aws-lc-sys = "=0.28.0"
|
||||||
|
aws-lc-rs = "=1.13.0"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
napi-build = "2.1"
|
napi-build = "2.1"
|
||||||
|
|||||||
@@ -1506,7 +1506,9 @@ describe.each([arrow15, arrow16, arrow17, arrow18])(
|
|||||||
];
|
];
|
||||||
const table = await db.createTable("test", data);
|
const table = await db.createTable("test", data);
|
||||||
await table.createIndex("text", {
|
await table.createIndex("text", {
|
||||||
config: Index.fts(),
|
config: Index.fts({
|
||||||
|
withPosition: true,
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const results = await table.search("lance").toArray();
|
const results = await table.search("lance").toArray();
|
||||||
@@ -1559,7 +1561,9 @@ describe.each([arrow15, arrow16, arrow17, arrow18])(
|
|||||||
];
|
];
|
||||||
const table = await db.createTable("test", data);
|
const table = await db.createTable("test", data);
|
||||||
await table.createIndex("text", {
|
await table.createIndex("text", {
|
||||||
config: Index.fts(),
|
config: Index.fts({
|
||||||
|
withPosition: true,
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const results = await table.search("world").toArray();
|
const results = await table.search("world").toArray();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@lancedb/lancedb-darwin-arm64",
|
"name": "@lancedb/lancedb-darwin-arm64",
|
||||||
"version": "0.19.1-beta.3",
|
"version": "0.20.0-beta.2",
|
||||||
"os": ["darwin"],
|
"os": ["darwin"],
|
||||||
"cpu": ["arm64"],
|
"cpu": ["arm64"],
|
||||||
"main": "lancedb.darwin-arm64.node",
|
"main": "lancedb.darwin-arm64.node",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@lancedb/lancedb-darwin-x64",
|
"name": "@lancedb/lancedb-darwin-x64",
|
||||||
"version": "0.19.1-beta.3",
|
"version": "0.20.0-beta.2",
|
||||||
"os": ["darwin"],
|
"os": ["darwin"],
|
||||||
"cpu": ["x64"],
|
"cpu": ["x64"],
|
||||||
"main": "lancedb.darwin-x64.node",
|
"main": "lancedb.darwin-x64.node",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@lancedb/lancedb-linux-arm64-gnu",
|
"name": "@lancedb/lancedb-linux-arm64-gnu",
|
||||||
"version": "0.19.1-beta.3",
|
"version": "0.20.0-beta.2",
|
||||||
"os": ["linux"],
|
"os": ["linux"],
|
||||||
"cpu": ["arm64"],
|
"cpu": ["arm64"],
|
||||||
"main": "lancedb.linux-arm64-gnu.node",
|
"main": "lancedb.linux-arm64-gnu.node",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@lancedb/lancedb-linux-arm64-musl",
|
"name": "@lancedb/lancedb-linux-arm64-musl",
|
||||||
"version": "0.19.1-beta.3",
|
"version": "0.20.0-beta.2",
|
||||||
"os": ["linux"],
|
"os": ["linux"],
|
||||||
"cpu": ["arm64"],
|
"cpu": ["arm64"],
|
||||||
"main": "lancedb.linux-arm64-musl.node",
|
"main": "lancedb.linux-arm64-musl.node",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@lancedb/lancedb-linux-x64-gnu",
|
"name": "@lancedb/lancedb-linux-x64-gnu",
|
||||||
"version": "0.19.1-beta.3",
|
"version": "0.20.0-beta.2",
|
||||||
"os": ["linux"],
|
"os": ["linux"],
|
||||||
"cpu": ["x64"],
|
"cpu": ["x64"],
|
||||||
"main": "lancedb.linux-x64-gnu.node",
|
"main": "lancedb.linux-x64-gnu.node",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@lancedb/lancedb-linux-x64-musl",
|
"name": "@lancedb/lancedb-linux-x64-musl",
|
||||||
"version": "0.19.1-beta.3",
|
"version": "0.20.0-beta.2",
|
||||||
"os": ["linux"],
|
"os": ["linux"],
|
||||||
"cpu": ["x64"],
|
"cpu": ["x64"],
|
||||||
"main": "lancedb.linux-x64-musl.node",
|
"main": "lancedb.linux-x64-musl.node",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@lancedb/lancedb-win32-arm64-msvc",
|
"name": "@lancedb/lancedb-win32-arm64-msvc",
|
||||||
"version": "0.19.1-beta.3",
|
"version": "0.20.0-beta.2",
|
||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@lancedb/lancedb-win32-x64-msvc",
|
"name": "@lancedb/lancedb-win32-x64-msvc",
|
||||||
"version": "0.19.1-beta.3",
|
"version": "0.20.0-beta.2",
|
||||||
"os": ["win32"],
|
"os": ["win32"],
|
||||||
"cpu": ["x64"],
|
"cpu": ["x64"],
|
||||||
"main": "lancedb.win32-x64-msvc.node",
|
"main": "lancedb.win32-x64-msvc.node",
|
||||||
|
|||||||
4
nodejs/package-lock.json
generated
4
nodejs/package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@lancedb/lancedb",
|
"name": "@lancedb/lancedb",
|
||||||
"version": "0.19.1-beta.3",
|
"version": "0.20.0-beta.2",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@lancedb/lancedb",
|
"name": "@lancedb/lancedb",
|
||||||
"version": "0.19.1-beta.3",
|
"version": "0.20.0-beta.2",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64",
|
"x64",
|
||||||
"arm64"
|
"arm64"
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
"ann"
|
"ann"
|
||||||
],
|
],
|
||||||
"private": false,
|
"private": false,
|
||||||
"version": "0.19.1-beta.3",
|
"version": "0.20.0-beta.2",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./dist/index.js",
|
".": "./dist/index.js",
|
||||||
|
|||||||
@@ -125,32 +125,30 @@ impl Index {
|
|||||||
ascii_folding: Option<bool>,
|
ascii_folding: Option<bool>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut opts = FtsIndexBuilder::default();
|
let mut opts = FtsIndexBuilder::default();
|
||||||
let mut tokenizer_configs = opts.tokenizer_configs.clone();
|
|
||||||
if let Some(with_position) = with_position {
|
if let Some(with_position) = with_position {
|
||||||
opts = opts.with_position(with_position);
|
opts = opts.with_position(with_position);
|
||||||
}
|
}
|
||||||
if let Some(base_tokenizer) = base_tokenizer {
|
if let Some(base_tokenizer) = base_tokenizer {
|
||||||
tokenizer_configs = tokenizer_configs.base_tokenizer(base_tokenizer);
|
opts = opts.base_tokenizer(base_tokenizer);
|
||||||
}
|
}
|
||||||
if let Some(language) = language {
|
if let Some(language) = language {
|
||||||
tokenizer_configs = tokenizer_configs.language(&language).unwrap();
|
opts = opts.language(&language).unwrap();
|
||||||
}
|
}
|
||||||
if let Some(max_token_length) = max_token_length {
|
if let Some(max_token_length) = max_token_length {
|
||||||
tokenizer_configs = tokenizer_configs.max_token_length(Some(max_token_length as usize));
|
opts = opts.max_token_length(Some(max_token_length as usize));
|
||||||
}
|
}
|
||||||
if let Some(lower_case) = lower_case {
|
if let Some(lower_case) = lower_case {
|
||||||
tokenizer_configs = tokenizer_configs.lower_case(lower_case);
|
opts = opts.lower_case(lower_case);
|
||||||
}
|
}
|
||||||
if let Some(stem) = stem {
|
if let Some(stem) = stem {
|
||||||
tokenizer_configs = tokenizer_configs.stem(stem);
|
opts = opts.stem(stem);
|
||||||
}
|
}
|
||||||
if let Some(remove_stop_words) = remove_stop_words {
|
if let Some(remove_stop_words) = remove_stop_words {
|
||||||
tokenizer_configs = tokenizer_configs.remove_stop_words(remove_stop_words);
|
opts = opts.remove_stop_words(remove_stop_words);
|
||||||
}
|
}
|
||||||
if let Some(ascii_folding) = ascii_folding {
|
if let Some(ascii_folding) = ascii_folding {
|
||||||
tokenizer_configs = tokenizer_configs.ascii_folding(ascii_folding);
|
opts = opts.ascii_folding(ascii_folding);
|
||||||
}
|
}
|
||||||
opts.tokenizer_configs = tokenizer_configs;
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
inner: Mutex::new(Some(LanceDbIndex::FTS(opts))),
|
inner: Mutex::new(Some(LanceDbIndex::FTS(opts))),
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[tool.bumpversion]
|
[tool.bumpversion]
|
||||||
current_version = "0.22.1-beta.4"
|
current_version = "0.23.0"
|
||||||
parse = """(?x)
|
parse = """(?x)
|
||||||
(?P<major>0|[1-9]\\d*)\\.
|
(?P<major>0|[1-9]\\d*)\\.
|
||||||
(?P<minor>0|[1-9]\\d*)\\.
|
(?P<minor>0|[1-9]\\d*)\\.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "lancedb-python"
|
name = "lancedb-python"
|
||||||
version = "0.22.1-beta.4"
|
version = "0.23.0"
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
description = "Python bindings for LanceDB"
|
description = "Python bindings for LanceDB"
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
@@ -14,11 +14,11 @@ name = "_lancedb"
|
|||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
arrow = { version = "54.1", features = ["pyarrow"] }
|
arrow = { version = "55.1", features = ["pyarrow"] }
|
||||||
lancedb = { path = "../rust/lancedb", default-features = false }
|
lancedb = { path = "../rust/lancedb", default-features = false }
|
||||||
env_logger.workspace = true
|
env_logger.workspace = true
|
||||||
pyo3 = { version = "0.23", features = ["extension-module", "abi3-py39"] }
|
pyo3 = { version = "0.24", features = ["extension-module", "abi3-py39"] }
|
||||||
pyo3-async-runtimes = { version = "0.23", features = [
|
pyo3-async-runtimes = { version = "0.24", features = [
|
||||||
"attributes",
|
"attributes",
|
||||||
"tokio-runtime",
|
"tokio-runtime",
|
||||||
] }
|
] }
|
||||||
@@ -27,7 +27,7 @@ futures.workspace = true
|
|||||||
tokio = { version = "1.40", features = ["sync"] }
|
tokio = { version = "1.40", features = ["sync"] }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
pyo3-build-config = { version = "0.23", features = [
|
pyo3-build-config = { version = "0.24", features = [
|
||||||
"extension-module",
|
"extension-module",
|
||||||
"abi3-py39",
|
"abi3-py39",
|
||||||
] }
|
] }
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ tests = [
|
|||||||
"pyarrow-stubs",
|
"pyarrow-stubs",
|
||||||
"pylance>=0.25",
|
"pylance>=0.25",
|
||||||
"requests",
|
"requests",
|
||||||
|
"datafusion",
|
||||||
]
|
]
|
||||||
dev = [
|
dev = [
|
||||||
"ruff",
|
"ruff",
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ class FTS:
|
|||||||
|
|
||||||
Attributes
|
Attributes
|
||||||
----------
|
----------
|
||||||
with_position : bool, default True
|
with_position : bool, default False
|
||||||
Whether to store the position of the token in the document. Setting this
|
Whether to store the position of the token in the document. Setting this
|
||||||
to False can reduce the size of the index and improve indexing speed,
|
to False can reduce the size of the index and improve indexing speed,
|
||||||
but it will disable support for phrase queries.
|
but it will disable support for phrase queries.
|
||||||
@@ -118,25 +118,25 @@ class FTS:
|
|||||||
ignored.
|
ignored.
|
||||||
lower_case : bool, default True
|
lower_case : bool, default True
|
||||||
Whether to convert the token to lower case. This makes queries case-insensitive.
|
Whether to convert the token to lower case. This makes queries case-insensitive.
|
||||||
stem : bool, default False
|
stem : bool, default True
|
||||||
Whether to stem the token. Stemming reduces words to their root form.
|
Whether to stem the token. Stemming reduces words to their root form.
|
||||||
For example, in English "running" and "runs" would both be reduced to "run".
|
For example, in English "running" and "runs" would both be reduced to "run".
|
||||||
remove_stop_words : bool, default False
|
remove_stop_words : bool, default True
|
||||||
Whether to remove stop words. Stop words are common words that are often
|
Whether to remove stop words. Stop words are common words that are often
|
||||||
removed from text before indexing. For example, in English "the" and "and".
|
removed from text before indexing. For example, in English "the" and "and".
|
||||||
ascii_folding : bool, default False
|
ascii_folding : bool, default True
|
||||||
Whether to fold ASCII characters. This converts accented characters to
|
Whether to fold ASCII characters. This converts accented characters to
|
||||||
their ASCII equivalent. For example, "café" would be converted to "cafe".
|
their ASCII equivalent. For example, "café" would be converted to "cafe".
|
||||||
"""
|
"""
|
||||||
|
|
||||||
with_position: bool = True
|
with_position: bool = False
|
||||||
base_tokenizer: Literal["simple", "raw", "whitespace"] = "simple"
|
base_tokenizer: Literal["simple", "raw", "whitespace"] = "simple"
|
||||||
language: str = "English"
|
language: str = "English"
|
||||||
max_token_length: Optional[int] = 40
|
max_token_length: Optional[int] = 40
|
||||||
lower_case: bool = True
|
lower_case: bool = True
|
||||||
stem: bool = False
|
stem: bool = True
|
||||||
remove_stop_words: bool = False
|
remove_stop_words: bool = True
|
||||||
ascii_folding: bool = False
|
ascii_folding: bool = True
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|||||||
@@ -149,15 +149,15 @@ class RemoteTable(Table):
|
|||||||
*,
|
*,
|
||||||
replace: bool = False,
|
replace: bool = False,
|
||||||
wait_timeout: timedelta = None,
|
wait_timeout: timedelta = None,
|
||||||
with_position: bool = True,
|
with_position: bool = False,
|
||||||
# tokenizer configs:
|
# tokenizer configs:
|
||||||
base_tokenizer: str = "simple",
|
base_tokenizer: str = "simple",
|
||||||
language: str = "English",
|
language: str = "English",
|
||||||
max_token_length: Optional[int] = 40,
|
max_token_length: Optional[int] = 40,
|
||||||
lower_case: bool = True,
|
lower_case: bool = True,
|
||||||
stem: bool = False,
|
stem: bool = True,
|
||||||
remove_stop_words: bool = False,
|
remove_stop_words: bool = True,
|
||||||
ascii_folding: bool = False,
|
ascii_folding: bool = True,
|
||||||
):
|
):
|
||||||
config = FTS(
|
config = FTS(
|
||||||
with_position=with_position,
|
with_position=with_position,
|
||||||
|
|||||||
@@ -829,15 +829,15 @@ class Table(ABC):
|
|||||||
writer_heap_size: Optional[int] = 1024 * 1024 * 1024,
|
writer_heap_size: Optional[int] = 1024 * 1024 * 1024,
|
||||||
use_tantivy: bool = True,
|
use_tantivy: bool = True,
|
||||||
tokenizer_name: Optional[str] = None,
|
tokenizer_name: Optional[str] = None,
|
||||||
with_position: bool = True,
|
with_position: bool = False,
|
||||||
# tokenizer configs:
|
# tokenizer configs:
|
||||||
base_tokenizer: BaseTokenizerType = "simple",
|
base_tokenizer: BaseTokenizerType = "simple",
|
||||||
language: str = "English",
|
language: str = "English",
|
||||||
max_token_length: Optional[int] = 40,
|
max_token_length: Optional[int] = 40,
|
||||||
lower_case: bool = True,
|
lower_case: bool = True,
|
||||||
stem: bool = False,
|
stem: bool = True,
|
||||||
remove_stop_words: bool = False,
|
remove_stop_words: bool = True,
|
||||||
ascii_folding: bool = False,
|
ascii_folding: bool = True,
|
||||||
wait_timeout: Optional[timedelta] = None,
|
wait_timeout: Optional[timedelta] = None,
|
||||||
):
|
):
|
||||||
"""Create a full-text search index on the table.
|
"""Create a full-text search index on the table.
|
||||||
@@ -867,7 +867,7 @@ class Table(ABC):
|
|||||||
use_tantivy: bool, default True
|
use_tantivy: bool, default True
|
||||||
If True, use the legacy full-text search implementation based on tantivy.
|
If True, use the legacy full-text search implementation based on tantivy.
|
||||||
If False, use the new full-text search implementation based on lance-index.
|
If False, use the new full-text search implementation based on lance-index.
|
||||||
with_position: bool, default True
|
with_position: bool, default False
|
||||||
Only available with use_tantivy=False
|
Only available with use_tantivy=False
|
||||||
If False, do not store the positions of the terms in the text.
|
If False, do not store the positions of the terms in the text.
|
||||||
This can reduce the size of the index and improve indexing speed.
|
This can reduce the size of the index and improve indexing speed.
|
||||||
@@ -885,13 +885,13 @@ class Table(ABC):
|
|||||||
lower_case : bool, default True
|
lower_case : bool, default True
|
||||||
Whether to convert the token to lower case. This makes queries
|
Whether to convert the token to lower case. This makes queries
|
||||||
case-insensitive.
|
case-insensitive.
|
||||||
stem : bool, default False
|
stem : bool, default True
|
||||||
Whether to stem the token. Stemming reduces words to their root form.
|
Whether to stem the token. Stemming reduces words to their root form.
|
||||||
For example, in English "running" and "runs" would both be reduced to "run".
|
For example, in English "running" and "runs" would both be reduced to "run".
|
||||||
remove_stop_words : bool, default False
|
remove_stop_words : bool, default True
|
||||||
Whether to remove stop words. Stop words are common words that are often
|
Whether to remove stop words. Stop words are common words that are often
|
||||||
removed from text before indexing. For example, in English "the" and "and".
|
removed from text before indexing. For example, in English "the" and "and".
|
||||||
ascii_folding : bool, default False
|
ascii_folding : bool, default True
|
||||||
Whether to fold ASCII characters. This converts accented characters to
|
Whether to fold ASCII characters. This converts accented characters to
|
||||||
their ASCII equivalent. For example, "café" would be converted to "cafe".
|
their ASCII equivalent. For example, "café" would be converted to "cafe".
|
||||||
wait_timeout: timedelta, optional
|
wait_timeout: timedelta, optional
|
||||||
@@ -1972,15 +1972,15 @@ class LanceTable(Table):
|
|||||||
writer_heap_size: Optional[int] = 1024 * 1024 * 1024,
|
writer_heap_size: Optional[int] = 1024 * 1024 * 1024,
|
||||||
use_tantivy: bool = True,
|
use_tantivy: bool = True,
|
||||||
tokenizer_name: Optional[str] = None,
|
tokenizer_name: Optional[str] = None,
|
||||||
with_position: bool = True,
|
with_position: bool = False,
|
||||||
# tokenizer configs:
|
# tokenizer configs:
|
||||||
base_tokenizer: BaseTokenizerType = "simple",
|
base_tokenizer: BaseTokenizerType = "simple",
|
||||||
language: str = "English",
|
language: str = "English",
|
||||||
max_token_length: Optional[int] = 40,
|
max_token_length: Optional[int] = 40,
|
||||||
lower_case: bool = True,
|
lower_case: bool = True,
|
||||||
stem: bool = False,
|
stem: bool = True,
|
||||||
remove_stop_words: bool = False,
|
remove_stop_words: bool = True,
|
||||||
ascii_folding: bool = False,
|
ascii_folding: bool = True,
|
||||||
):
|
):
|
||||||
if not use_tantivy:
|
if not use_tantivy:
|
||||||
if not isinstance(field_names, str):
|
if not isinstance(field_names, str):
|
||||||
@@ -1990,6 +1990,7 @@ class LanceTable(Table):
|
|||||||
tokenizer_configs = {
|
tokenizer_configs = {
|
||||||
"base_tokenizer": base_tokenizer,
|
"base_tokenizer": base_tokenizer,
|
||||||
"language": language,
|
"language": language,
|
||||||
|
"with_position": with_position,
|
||||||
"max_token_length": max_token_length,
|
"max_token_length": max_token_length,
|
||||||
"lower_case": lower_case,
|
"lower_case": lower_case,
|
||||||
"stem": stem,
|
"stem": stem,
|
||||||
@@ -2000,7 +2001,6 @@ class LanceTable(Table):
|
|||||||
tokenizer_configs = self.infer_tokenizer_configs(tokenizer_name)
|
tokenizer_configs = self.infer_tokenizer_configs(tokenizer_name)
|
||||||
|
|
||||||
config = FTS(
|
config = FTS(
|
||||||
with_position=with_position,
|
|
||||||
**tokenizer_configs,
|
**tokenizer_configs,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,10 @@ import numpy as np
|
|||||||
from lancedb.pydantic import Vector, LanceModel
|
from lancedb.pydantic import Vector, LanceModel
|
||||||
|
|
||||||
# --8<-- [end:import-lancedb-pydantic]
|
# --8<-- [end:import-lancedb-pydantic]
|
||||||
|
# --8<-- [start:import-session-context]
|
||||||
|
from datafusion import SessionContext
|
||||||
|
|
||||||
|
# --8<-- [end:import-session-context]
|
||||||
# --8<-- [start:import-datetime]
|
# --8<-- [start:import-datetime]
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
@@ -33,6 +37,10 @@ from datetime import timedelta
|
|||||||
from lancedb.embeddings import get_registry
|
from lancedb.embeddings import get_registry
|
||||||
|
|
||||||
# --8<-- [end:import-embeddings]
|
# --8<-- [end:import-embeddings]
|
||||||
|
# --8<-- [start:import-ffi-dataset]
|
||||||
|
from lance import FFILanceTableProvider
|
||||||
|
|
||||||
|
# --8<-- [end:import-ffi-dataset]
|
||||||
# --8<-- [start:import-pydantic-basemodel]
|
# --8<-- [start:import-pydantic-basemodel]
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
@@ -341,6 +349,27 @@ def test_table_with_embedding():
|
|||||||
# --8<-- [end:create_table_with_embedding]
|
# --8<-- [end:create_table_with_embedding]
|
||||||
|
|
||||||
|
|
||||||
|
def test_sql_query():
|
||||||
|
db = lancedb.connect("data/sample-lancedb")
|
||||||
|
data = [
|
||||||
|
{"vector": [1.1, 1.2], "lat": 45.5, "long": -122.7},
|
||||||
|
{"vector": [0.2, 1.8], "lat": 40.1, "long": -74.1},
|
||||||
|
]
|
||||||
|
table = db.create_table("lance_table", data)
|
||||||
|
|
||||||
|
# --8<-- [start:lance_sql_basic]
|
||||||
|
ctx = SessionContext()
|
||||||
|
ffi_lance_table = FFILanceTableProvider(
|
||||||
|
table.to_lance(), with_row_id=False, with_row_addr=False
|
||||||
|
)
|
||||||
|
|
||||||
|
ctx.register_table_provider("ffi_lance_table", ffi_lance_table)
|
||||||
|
ctx.table("ffi_lance_table")
|
||||||
|
|
||||||
|
ctx.sql("SELECT vector FROM ffi_lance_table")
|
||||||
|
# --8<-- [end:lance_sql_basic]
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skip
|
@pytest.mark.skip
|
||||||
async def test_table_with_embedding_async():
|
async def test_table_with_embedding_async():
|
||||||
async_db = await lancedb.connect_async("data/sample-lancedb")
|
async_db = await lancedb.connect_async("data/sample-lancedb")
|
||||||
|
|||||||
@@ -156,6 +156,9 @@ async def test_vector_search_async():
|
|||||||
# --8<-- [end:search_result_async_as_list]
|
# --8<-- [end:search_result_async_as_list]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(
|
||||||
|
os.name == "nt", reason="Need to fix https://github.com/lancedb/lance/issues/3905"
|
||||||
|
)
|
||||||
def test_fts_fuzzy_query():
|
def test_fts_fuzzy_query():
|
||||||
uri = "data/fuzzy-example"
|
uri = "data/fuzzy-example"
|
||||||
db = lancedb.connect(uri)
|
db = lancedb.connect(uri)
|
||||||
@@ -189,6 +192,9 @@ def test_fts_fuzzy_query():
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(
|
||||||
|
os.name == "nt", reason="Need to fix https://github.com/lancedb/lance/issues/3905"
|
||||||
|
)
|
||||||
def test_fts_boost_query():
|
def test_fts_boost_query():
|
||||||
uri = "data/boost-example"
|
uri = "data/boost-example"
|
||||||
db = lancedb.connect(uri)
|
db = lancedb.connect(uri)
|
||||||
@@ -234,6 +240,9 @@ def test_fts_boost_query():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(
|
||||||
|
os.name == "nt", reason="Need to fix https://github.com/lancedb/lance/issues/3905"
|
||||||
|
)
|
||||||
def test_fts_native():
|
def test_fts_native():
|
||||||
# --8<-- [start:basic_fts]
|
# --8<-- [start:basic_fts]
|
||||||
uri = "data/sample-lancedb"
|
uri = "data/sample-lancedb"
|
||||||
@@ -282,6 +291,9 @@ def test_fts_native():
|
|||||||
# --8<-- [end:fts_incremental_index]
|
# --8<-- [end:fts_incremental_index]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(
|
||||||
|
os.name == "nt", reason="Need to fix https://github.com/lancedb/lance/issues/3905"
|
||||||
|
)
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_fts_native_async():
|
async def test_fts_native_async():
|
||||||
# --8<-- [start:basic_fts_async]
|
# --8<-- [start:basic_fts_async]
|
||||||
|
|||||||
@@ -287,7 +287,7 @@ def test_search_fts_phrase_query(table):
|
|||||||
assert False
|
assert False
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
table.create_fts_index("text", use_tantivy=False, replace=True)
|
table.create_fts_index("text", use_tantivy=False, with_position=True, replace=True)
|
||||||
results = table.search("puppy").limit(100).to_list()
|
results = table.search("puppy").limit(100).to_list()
|
||||||
phrase_results = table.search('"puppy runs"').limit(100).to_list()
|
phrase_results = table.search('"puppy runs"').limit(100).to_list()
|
||||||
assert len(results) > len(phrase_results)
|
assert len(results) > len(phrase_results)
|
||||||
@@ -312,7 +312,7 @@ async def test_search_fts_phrase_query_async(async_table):
|
|||||||
assert False
|
assert False
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
await async_table.create_index("text", config=FTS())
|
await async_table.create_index("text", config=FTS(with_position=True))
|
||||||
results = await async_table.query().nearest_to_text("puppy").limit(100).to_list()
|
results = await async_table.query().nearest_to_text("puppy").limit(100).to_list()
|
||||||
phrase_results = (
|
phrase_results = (
|
||||||
await async_table.query().nearest_to_text('"puppy runs"').limit(100).to_list()
|
await async_table.query().nearest_to_text('"puppy runs"').limit(100).to_list()
|
||||||
@@ -649,7 +649,7 @@ def test_fts_on_list(mem_db: DBConnection):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
table = mem_db.create_table("test", data=data)
|
table = mem_db.create_table("test", data=data)
|
||||||
table.create_fts_index("text", use_tantivy=False)
|
table.create_fts_index("text", use_tantivy=False, with_position=True)
|
||||||
|
|
||||||
res = table.search("lance").limit(5).to_list()
|
res = table.search("lance").limit(5).to_list()
|
||||||
assert len(res) == 3
|
assert len(res) == 3
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
use lancedb::index::vector::IvfFlatIndexBuilder;
|
use lancedb::index::vector::IvfFlatIndexBuilder;
|
||||||
use lancedb::index::{
|
use lancedb::index::{
|
||||||
scalar::{BTreeIndexBuilder, FtsIndexBuilder, TokenizerConfig},
|
scalar::{BTreeIndexBuilder, FtsIndexBuilder},
|
||||||
vector::{IvfHnswPqIndexBuilder, IvfHnswSqIndexBuilder, IvfPqIndexBuilder},
|
vector::{IvfHnswPqIndexBuilder, IvfHnswSqIndexBuilder, IvfPqIndexBuilder},
|
||||||
Index as LanceDbIndex,
|
Index as LanceDbIndex,
|
||||||
};
|
};
|
||||||
@@ -38,19 +38,17 @@ pub fn extract_index_params(source: &Option<Bound<'_, PyAny>>) -> PyResult<Lance
|
|||||||
"LabelList" => Ok(LanceDbIndex::LabelList(Default::default())),
|
"LabelList" => Ok(LanceDbIndex::LabelList(Default::default())),
|
||||||
"FTS" => {
|
"FTS" => {
|
||||||
let params = source.extract::<FtsParams>()?;
|
let params = source.extract::<FtsParams>()?;
|
||||||
let inner_opts = TokenizerConfig::default()
|
let inner_opts = FtsIndexBuilder::default()
|
||||||
.base_tokenizer(params.base_tokenizer)
|
.base_tokenizer(params.base_tokenizer)
|
||||||
.language(¶ms.language)
|
.language(¶ms.language)
|
||||||
.map_err(|_| PyValueError::new_err(format!("LanceDB does not support the requested language: '{}'", params.language)))?
|
.map_err(|_| PyValueError::new_err(format!("LanceDB does not support the requested language: '{}'", params.language)))?
|
||||||
|
.with_position(params.with_position)
|
||||||
.lower_case(params.lower_case)
|
.lower_case(params.lower_case)
|
||||||
.max_token_length(params.max_token_length)
|
.max_token_length(params.max_token_length)
|
||||||
.remove_stop_words(params.remove_stop_words)
|
.remove_stop_words(params.remove_stop_words)
|
||||||
.stem(params.stem)
|
.stem(params.stem)
|
||||||
.ascii_folding(params.ascii_folding);
|
.ascii_folding(params.ascii_folding);
|
||||||
let mut opts = FtsIndexBuilder::default()
|
Ok(LanceDbIndex::FTS(inner_opts))
|
||||||
.with_position(params.with_position);
|
|
||||||
opts.tokenizer_configs = inner_opts;
|
|
||||||
Ok(LanceDbIndex::FTS(opts))
|
|
||||||
},
|
},
|
||||||
"IvfFlat" => {
|
"IvfFlat" => {
|
||||||
let params = source.extract::<IvfFlatParams>()?;
|
let params = source.extract::<IvfFlatParams>()?;
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "1.83.0"
|
channel = "1.86.0"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "lancedb-node"
|
name = "lancedb-node"
|
||||||
version = "0.19.1-beta.3"
|
version = "0.20.0-beta.2"
|
||||||
description = "Serverless, low-latency vector database for AI applications"
|
description = "Serverless, low-latency vector database for AI applications"
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "lancedb"
|
name = "lancedb"
|
||||||
version = "0.19.1-beta.3"
|
version = "0.20.0-beta.2"
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
description = "LanceDB: A serverless, low-latency vector database for AI applications"
|
description = "LanceDB: A serverless, low-latency vector database for AI applications"
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
@@ -60,15 +60,15 @@ reqwest = { version = "0.12.0", default-features = false, features = [
|
|||||||
"macos-system-configuration",
|
"macos-system-configuration",
|
||||||
"stream",
|
"stream",
|
||||||
], optional = true }
|
], optional = true }
|
||||||
rand = { version = "0.8.3", features = ["small_rng"], optional = true }
|
rand = { version = "0.9", features = ["small_rng"], optional = true }
|
||||||
http = { version = "1", optional = true } # Matching what is in reqwest
|
http = { version = "1", optional = true } # Matching what is in reqwest
|
||||||
uuid = { version = "1.7.0", features = ["v4"], optional = true }
|
uuid = { version = "1.7.0", features = ["v4"], optional = true }
|
||||||
polars-arrow = { version = ">=0.37,<0.40.0", optional = true }
|
polars-arrow = { version = ">=0.37,<0.40.0", optional = true }
|
||||||
polars = { version = ">=0.37,<0.40.0", optional = true }
|
polars = { version = ">=0.37,<0.40.0", optional = true }
|
||||||
hf-hub = { version = "0.4.1", optional = true, default-features = false, features = ["rustls-tls", "tokio", "ureq"]}
|
hf-hub = { version = "0.4.1", optional = true, default-features = false, features = ["rustls-tls", "tokio", "ureq"]}
|
||||||
candle-core = { version = "0.6.0", optional = true }
|
candle-core = { version = "0.9.1", optional = true }
|
||||||
candle-transformers = { version = "0.6.0", optional = true }
|
candle-transformers = { version = "0.9.1", optional = true }
|
||||||
candle-nn = { version = "0.6.0", optional = true }
|
candle-nn = { version = "0.9.1", optional = true }
|
||||||
tokenizers = { version = "0.19.1", optional = true }
|
tokenizers = { version = "0.19.1", optional = true }
|
||||||
semver = { workspace = true }
|
semver = { workspace = true }
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ bytemuck_derive.workspace = true
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempfile = "3.5.0"
|
tempfile = "3.5.0"
|
||||||
rand = { version = "0.8.3", features = ["small_rng"] }
|
rand = { version = "0.9", features = ["small_rng"] }
|
||||||
random_word = { version = "0.4.3", features = ["en"] }
|
random_word = { version = "0.4.3", features = ["en"] }
|
||||||
uuid = { version = "1.7.0", features = ["v4"] }
|
uuid = { version = "1.7.0", features = ["v4"] }
|
||||||
walkdir = "2"
|
walkdir = "2"
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ fn create_some_records() -> Result<Box<dyn RecordBatchReader + Send>> {
|
|||||||
Arc::new(Int32Array::from_iter_values(0..TOTAL as i32)),
|
Arc::new(Int32Array::from_iter_values(0..TOTAL as i32)),
|
||||||
Arc::new(StringArray::from_iter_values((0..TOTAL).map(|_| {
|
Arc::new(StringArray::from_iter_values((0..TOTAL).map(|_| {
|
||||||
(0..n_terms)
|
(0..n_terms)
|
||||||
.map(|_| words[random::<usize>() % words.len()])
|
.map(|_| words[random::<u32>() as usize % words.len()])
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(" ")
|
.join(" ")
|
||||||
}))),
|
}))),
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ impl SentenceTransformersEmbeddings {
|
|||||||
|
|
||||||
let embeddings = self
|
let embeddings = self
|
||||||
.model
|
.model
|
||||||
.forward(&input_ids, &token_type_ids)
|
.forward(&input_ids, &token_type_ids, None)
|
||||||
// TODO: it'd be nice to support other devices
|
// TODO: it'd be nice to support other devices
|
||||||
.and_then(|output| output.to_device(&Device::Cpu))?;
|
.and_then(|output| output.to_device(&Device::Cpu))?;
|
||||||
|
|
||||||
@@ -310,7 +310,7 @@ impl SentenceTransformersEmbeddings {
|
|||||||
let embeddings = Tensor::stack(&tokens, 0)
|
let embeddings = Tensor::stack(&tokens, 0)
|
||||||
.and_then(|tokens| {
|
.and_then(|tokens| {
|
||||||
let token_type_ids = tokens.zeros_like()?;
|
let token_type_ids = tokens.zeros_like()?;
|
||||||
self.model.forward(&tokens, &token_type_ids)
|
self.model.forward(&tokens, &token_type_ids, None)
|
||||||
})
|
})
|
||||||
// TODO: it'd be nice to support other devices
|
// TODO: it'd be nice to support other devices
|
||||||
.and_then(|tokens| tokens.to_device(&Device::Cpu))
|
.and_then(|tokens| tokens.to_device(&Device::Cpu))
|
||||||
|
|||||||
@@ -51,35 +51,7 @@ pub struct BitmapIndexBuilder {}
|
|||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct LabelListIndexBuilder {}
|
pub struct LabelListIndexBuilder {}
|
||||||
|
|
||||||
/// Builder for a full text search index
|
|
||||||
///
|
|
||||||
/// A full text search index is an index on a string column that allows for full text search
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct FtsIndexBuilder {
|
|
||||||
/// Whether to store the position of the tokens
|
|
||||||
/// This is used for phrase queries
|
|
||||||
pub with_position: bool,
|
|
||||||
|
|
||||||
pub tokenizer_configs: TokenizerConfig,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for FtsIndexBuilder {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
with_position: true,
|
|
||||||
tokenizer_configs: TokenizerConfig::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FtsIndexBuilder {
|
|
||||||
/// Set the with_position flag
|
|
||||||
pub fn with_position(mut self, with_position: bool) -> Self {
|
|
||||||
self.with_position = with_position;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub use lance_index::scalar::inverted::query::*;
|
pub use lance_index::scalar::inverted::query::*;
|
||||||
pub use lance_index::scalar::inverted::TokenizerConfig;
|
|
||||||
pub use lance_index::scalar::FullTextSearchQuery;
|
pub use lance_index::scalar::FullTextSearchQuery;
|
||||||
|
pub use lance_index::scalar::InvertedIndexParams as FtsIndexBuilder;
|
||||||
|
pub use lance_index::scalar::InvertedIndexParams;
|
||||||
|
|||||||
@@ -197,16 +197,8 @@ mod test {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_e2e() {
|
async fn test_e2e() {
|
||||||
let dir1 = tempfile::tempdir()
|
let dir1 = tempfile::tempdir().unwrap().keep().canonicalize().unwrap();
|
||||||
.unwrap()
|
let dir2 = tempfile::tempdir().unwrap().keep().canonicalize().unwrap();
|
||||||
.into_path()
|
|
||||||
.canonicalize()
|
|
||||||
.unwrap();
|
|
||||||
let dir2 = tempfile::tempdir()
|
|
||||||
.unwrap()
|
|
||||||
.into_path()
|
|
||||||
.canonicalize()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let secondary_store = LocalFileSystem::new_with_prefix(dir2.to_str().unwrap()).unwrap();
|
let secondary_store = LocalFileSystem::new_with_prefix(dir2.to_str().unwrap()).unwrap();
|
||||||
let object_store_wrapper = Arc::new(MirroringObjectStoreWrapper {
|
let object_store_wrapper = Arc::new(MirroringObjectStoreWrapper {
|
||||||
|
|||||||
@@ -995,16 +995,12 @@ impl<S: HttpSend> BaseTable for RemoteTable<S> {
|
|||||||
Index::Bitmap(_) => ("BITMAP", None),
|
Index::Bitmap(_) => ("BITMAP", None),
|
||||||
Index::LabelList(_) => ("LABEL_LIST", None),
|
Index::LabelList(_) => ("LABEL_LIST", None),
|
||||||
Index::FTS(fts) => {
|
Index::FTS(fts) => {
|
||||||
let with_position = fts.with_position;
|
let params = serde_json::to_value(&fts).map_err(|e| Error::InvalidInput {
|
||||||
let configs = serde_json::to_value(fts.tokenizer_configs).map_err(|e| {
|
message: format!("failed to serialize FTS index params {:?}", e),
|
||||||
Error::InvalidInput {
|
|
||||||
message: format!("failed to serialize FTS index params {:?}", e),
|
|
||||||
}
|
|
||||||
})?;
|
})?;
|
||||||
for (key, value) in configs.as_object().unwrap() {
|
for (key, value) in params.as_object().unwrap() {
|
||||||
body[key] = value.clone();
|
body[key] = value.clone();
|
||||||
}
|
}
|
||||||
body["with_position"] = serde_json::Value::Bool(with_position);
|
|
||||||
("FTS", None)
|
("FTS", None)
|
||||||
}
|
}
|
||||||
Index::Auto => {
|
Index::Auto => {
|
||||||
@@ -2460,14 +2456,10 @@ mod tests {
|
|||||||
expected_body["metric_type"] = distance_type.to_lowercase().into();
|
expected_body["metric_type"] = distance_type.to_lowercase().into();
|
||||||
}
|
}
|
||||||
if let Index::FTS(fts) = ¶ms {
|
if let Index::FTS(fts) = ¶ms {
|
||||||
expected_body["with_position"] = fts.with_position.into();
|
let params = serde_json::to_value(fts).unwrap();
|
||||||
expected_body["base_tokenizer"] = "simple".into();
|
for (key, value) in params.as_object().unwrap() {
|
||||||
expected_body["language"] = "English".into();
|
expected_body[key] = value.clone();
|
||||||
expected_body["max_token_length"] = 40.into();
|
}
|
||||||
expected_body["lower_case"] = true.into();
|
|
||||||
expected_body["stem"] = false.into();
|
|
||||||
expected_body["remove_stop_words"] = false.into();
|
|
||||||
expected_body["ascii_folding"] = false.into();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(body, expected_body);
|
assert_eq!(body, expected_body);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ use datafusion_physical_plan::projection::ProjectionExec;
|
|||||||
use datafusion_physical_plan::repartition::RepartitionExec;
|
use datafusion_physical_plan::repartition::RepartitionExec;
|
||||||
use datafusion_physical_plan::union::UnionExec;
|
use datafusion_physical_plan::union::UnionExec;
|
||||||
use datafusion_physical_plan::ExecutionPlan;
|
use datafusion_physical_plan::ExecutionPlan;
|
||||||
use futures::{FutureExt, StreamExt, TryFutureExt, TryStreamExt};
|
use futures::{FutureExt, StreamExt, TryFutureExt};
|
||||||
use lance::dataset::builder::DatasetBuilder;
|
use lance::dataset::builder::DatasetBuilder;
|
||||||
use lance::dataset::cleanup::RemovalStats;
|
use lance::dataset::cleanup::RemovalStats;
|
||||||
use lance::dataset::optimize::{compact_files, CompactionMetrics, IndexRemapperOptions};
|
use lance::dataset::optimize::{compact_files, CompactionMetrics, IndexRemapperOptions};
|
||||||
@@ -85,6 +85,7 @@ pub use lance::dataset::optimize::CompactionOptions;
|
|||||||
pub use lance::dataset::refs::{TagContents, Tags as LanceTags};
|
pub use lance::dataset::refs::{TagContents, Tags as LanceTags};
|
||||||
pub use lance::dataset::scanner::DatasetRecordBatchStream;
|
pub use lance::dataset::scanner::DatasetRecordBatchStream;
|
||||||
use lance::dataset::statistics::DatasetStatisticsExt;
|
use lance::dataset::statistics::DatasetStatisticsExt;
|
||||||
|
use lance_index::frag_reuse::FRAG_REUSE_INDEX_NAME;
|
||||||
pub use lance_index::optimize::OptimizeOptions;
|
pub use lance_index::optimize::OptimizeOptions;
|
||||||
use serde_with::skip_serializing_none;
|
use serde_with::skip_serializing_none;
|
||||||
|
|
||||||
@@ -1977,16 +1978,12 @@ impl NativeTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut dataset = self.dataset.get_mut().await?;
|
let mut dataset = self.dataset.get_mut().await?;
|
||||||
let fts_params = lance_index::scalar::InvertedIndexParams {
|
|
||||||
with_position: fts_opts.with_position,
|
|
||||||
tokenizer_config: fts_opts.tokenizer_configs,
|
|
||||||
};
|
|
||||||
dataset
|
dataset
|
||||||
.create_index(
|
.create_index(
|
||||||
&[field.name()],
|
&[field.name()],
|
||||||
IndexType::Inverted,
|
IndexType::Inverted,
|
||||||
None,
|
None,
|
||||||
&fts_params,
|
&fts_opts,
|
||||||
replace,
|
replace,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
@@ -2605,28 +2602,56 @@ impl BaseTable for NativeTable {
|
|||||||
async fn list_indices(&self) -> Result<Vec<IndexConfig>> {
|
async fn list_indices(&self) -> Result<Vec<IndexConfig>> {
|
||||||
let dataset = self.dataset.get().await?;
|
let dataset = self.dataset.get().await?;
|
||||||
let indices = dataset.load_indices().await?;
|
let indices = dataset.load_indices().await?;
|
||||||
futures::stream::iter(indices.as_slice()).then(|idx| async {
|
let results = futures::stream::iter(indices.as_slice()).then(|idx| async {
|
||||||
let stats = dataset.index_statistics(idx.name.as_str()).await?;
|
|
||||||
let stats: serde_json::Value = serde_json::from_str(&stats).map_err(|e| Error::Runtime {
|
// skip Lance internal indexes
|
||||||
message: format!("error deserializing index statistics: {}", e),
|
if idx.name == FRAG_REUSE_INDEX_NAME {
|
||||||
})?;
|
return None;
|
||||||
let index_type = stats.get("index_type").and_then(|v| v.as_str())
|
}
|
||||||
.ok_or_else(|| Error::Runtime {
|
|
||||||
message: "index statistics was missing index type".to_string(),
|
let stats = match dataset.index_statistics(idx.name.as_str()).await {
|
||||||
})?;
|
Ok(stats) => stats,
|
||||||
let index_type: crate::index::IndexType = index_type.parse().map_err(|e| Error::Runtime {
|
Err(e) => {
|
||||||
message: format!("error parsing index type: {}", e),
|
log::warn!("Failed to get statistics for index {} ({}): {}", idx.name, idx.uuid, e);
|
||||||
})?;
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let stats: serde_json::Value = match serde_json::from_str(&stats) {
|
||||||
|
Ok(stats) => stats,
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("Failed to deserialize index statistics for index {} ({}): {}", idx.name, idx.uuid, e);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(index_type) = stats.get("index_type").and_then(|v| v.as_str()) else {
|
||||||
|
log::warn!("Index statistics was missing 'index_type' field for index {} ({})", idx.name, idx.uuid);
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
let index_type: crate::index::IndexType = match index_type.parse() {
|
||||||
|
Ok(index_type) => index_type,
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("Failed to parse index type for index {} ({}): {}", idx.name, idx.uuid, e);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let mut columns = Vec::with_capacity(idx.fields.len());
|
let mut columns = Vec::with_capacity(idx.fields.len());
|
||||||
for field_id in &idx.fields {
|
for field_id in &idx.fields {
|
||||||
let field = dataset.schema().field_by_id(*field_id).ok_or_else(|| Error::Runtime { message: format!("The index with name {} and uuid {} referenced a field with id {} which does not exist in the schema", idx.name, idx.uuid, field_id) })?;
|
let Some(field) = dataset.schema().field_by_id(*field_id) else {
|
||||||
|
log::warn!("The index {} ({}) referenced a field with id {} which does not exist in the schema", idx.name, idx.uuid, field_id);
|
||||||
|
return None;
|
||||||
|
};
|
||||||
columns.push(field.name.clone());
|
columns.push(field.name.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = idx.name.clone();
|
let name = idx.name.clone();
|
||||||
Ok(IndexConfig { index_type, columns, name })
|
Some(IndexConfig { index_type, columns, name })
|
||||||
}).try_collect::<Vec<_>>().await
|
}).collect::<Vec<_>>().await;
|
||||||
|
|
||||||
|
Ok(results.into_iter().flatten().collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dataset_uri(&self) -> &str {
|
fn dataset_uri(&self) -> &str {
|
||||||
@@ -2819,7 +2844,7 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::connect;
|
use crate::connect;
|
||||||
use crate::connection::ConnectBuilder;
|
use crate::connection::ConnectBuilder;
|
||||||
use crate::index::scalar::BTreeIndexBuilder;
|
use crate::index::scalar::{BTreeIndexBuilder, BitmapIndexBuilder};
|
||||||
use crate::query::{ExecutableQuery, QueryBase};
|
use crate::query::{ExecutableQuery, QueryBase};
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -4271,4 +4296,65 @@ mod tests {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
pub async fn test_list_indices_skip_frag_reuse() {
|
||||||
|
let tmp_dir = tempdir().unwrap();
|
||||||
|
let uri = tmp_dir.path().to_str().unwrap();
|
||||||
|
|
||||||
|
let conn = ConnectBuilder::new(uri).execute().await.unwrap();
|
||||||
|
|
||||||
|
let schema = Arc::new(Schema::new(vec![
|
||||||
|
Field::new("id", DataType::Int32, false),
|
||||||
|
Field::new("foo", DataType::Int32, true),
|
||||||
|
]));
|
||||||
|
let batch = RecordBatch::try_new(
|
||||||
|
schema.clone(),
|
||||||
|
vec![
|
||||||
|
Arc::new(Int32Array::from_iter_values(0..100)),
|
||||||
|
Arc::new(Int32Array::from_iter_values(0..100)),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let table = conn
|
||||||
|
.create_table(
|
||||||
|
"test_list_indices_skip_frag_reuse",
|
||||||
|
RecordBatchIterator::new(vec![Ok(batch.clone())], batch.schema()),
|
||||||
|
)
|
||||||
|
.execute()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
table
|
||||||
|
.add(RecordBatchIterator::new(
|
||||||
|
vec![Ok(batch.clone())],
|
||||||
|
batch.schema(),
|
||||||
|
))
|
||||||
|
.execute()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
table
|
||||||
|
.create_index(&["id"], Index::Bitmap(BitmapIndexBuilder {}))
|
||||||
|
.execute()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
table
|
||||||
|
.optimize(OptimizeAction::Compact {
|
||||||
|
options: CompactionOptions {
|
||||||
|
target_rows_per_fragment: 2_000,
|
||||||
|
defer_index_remap: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
remap_options: None,
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let result = table.list_indices().await.unwrap();
|
||||||
|
assert_eq!(result.len(), 1);
|
||||||
|
assert_eq!(result[0].index_type, crate::index::IndexType::Bitmap);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user