Compare commits

...

19 Commits

Author SHA1 Message Date
Lance Release
bb3df62dce Bump version: 0.1.9 → 0.1.10 2023-07-06 03:05:32 +00:00
Lei Xu
dc7146b2cb [Node] Expose IVF PQ config (#258) 2023-07-05 19:54:21 -07:00
Lei Xu
d701947f0b [Rust] Re-export WriteMode from lancedb instead of lance (#257)
`Table::add(.., mode: WriteMode)`, which is a public API, currently uses
the WriteMode exported from `lance`. Re-export it to lancedb so that the
pub API looks better.
2023-07-05 18:20:31 -07:00
Chang She
3c46d7f268 Handle NaN input data (#241)
Sometimes LangChain would insert a single `[np.nan]` as a placeholder if
the embedding function failed. This causes a problem for Lance format
because then the array can't be stored as a FixedSizedListArray.

Instead:
1. By default we remove rows with embedding lengths less than the
maximum length in the batch
2. If `strict=True` kwargs is set to True, then a `ValueError` is raised
if the embeddings aren't all the same length

---------

Co-authored-by: Chang She <chang@lancedb.com>
2023-07-04 20:00:46 -07:00
Leon Yee
9600a38ff0 [docs] fixed javascript docs for overloaded functions (#247)
Solves #244 :


![image](https://github.com/lancedb/lancedb/assets/43097991/d1fd9d2a-0d6a-4c16-a0ab-f460cc709349)

Problem was function overloading in the interface caused some weird
`typedoc` formatting, so breaking it apart into methods fixed the issue.

Also regenerated and updated javascript docs

---------

Co-authored-by: Tevin Wang <tevin@cmu.edu>
2023-07-04 13:07:34 -07:00
Lei Xu
148ed82607 Bump Lance version to 0.5.3 (#250) 2023-07-04 08:34:41 -07:00
Lei Xu
fc725c99f0 [Node] Create Table with WriteMode (#246)
Support `createTable(name, data, mode?)`  to be consistent with Python.

Closes #242
2023-07-03 17:04:21 -07:00
Rob Meng
a6bdffd75b bump lance to 0.5.2, make object store construction hook public (#237)
* bump to 0.5.2 to pick up S3 auth fixes
* make `open_table_params` a public attribute
* add `open_table_with_params` on `Database`
2023-06-29 18:50:02 -04:00
Lei Xu
051c03c3c9 Add dot product support (#239)
Closes #207
2023-06-29 10:32:01 -07:00
Tevin Wang
39479dcf8e fix sha error in npm (#236)
Currently getting a `npm ERR! code EINTEGRITY` on merge, need to fix
asap.


https://stackoverflow.com/questions/75905223/github-action-npm-install-give-code-eintegrity-integrity-checksum-failed
2023-06-29 09:31:23 -07:00
Tevin Wang
b731a6aed9 Add docs code testing & documentation syntax changes (#196)
- Creates testing files `md_testing.py` and `md_testing.js` for testing
python and nodejs code in markdown files in the documentation
This listens for HTML tags as well: `<!--[language] code code
code...-->` will create a set-up file to create some mock tables or to
fulfill some assumptions in the documentation.
- Creates a github action workflow that triggers every push/pr to
`docs/**`
- Modifies documentation so tests run (mostly indentation, some small
syntax errors and some missing imports)

A list of excluded files that we need to take a closer look at later on:
```javascript
const excludedFiles = [
  "../src/fts.md",
  "../src/embedding.md",
  "../src/examples/serverless_lancedb_with_s3_and_lambda.md",
  "../src/examples/serverless_qa_bot_with_modal_and_langchain.md",
  "../src/examples/youtube_transcript_bot_with_nodejs.md",
];
```
Many of them can't be done because we need the OpenAI API key :(.
`fts.md` has some issues with the library, I believe this is still
experimental?

Closes #170

---------

Co-authored-by: Will Jones <willjones127@gmail.com>
2023-06-28 11:07:26 -07:00
Rob Meng
0f58bd7af2 allow passing ReadParams to dataset when opening a table (#234)
Plumb thru object store construction hook from
[lance/pull/1014](https://github.com/lancedb/lance/pull/1014)
2023-06-28 11:20:09 -04:00
Rob Meng
01abf82808 Refactor TS client to use interface + implementation pattern (#226)
## What?
* Changed `Connection` and `Table` to interfaces
* Renamed original `Connection` and `Table` to `LocalConnection` and
`LocalTable`
2023-06-27 21:45:01 -04:00
Leon Yee
eb5bcda337 Error implementations (#232)
Solves #216 by adding a check on table open for existence of the
`.lance` file. Does not check for it for remote connections.
2023-06-27 16:48:31 -07:00
Lei Xu
4bc676e26a [Python] Support replace during create_index (#233)
Closes #214
2023-06-27 16:02:07 -07:00
Lei Xu
c68c236f17 [Js] Create index with replace flag (#229) 2023-06-26 18:38:20 -07:00
Philip Kung
313e66c4c5 Specify and Index Column for Vector Search (#217) 2023-06-26 16:11:08 -07:00
Lei Xu
e850df56f1 fix requirements 2023-06-26 12:25:29 -07:00
Lei Xu
8c5507075c Sql filter document (#228) 2023-06-26 12:22:22 -07:00
56 changed files with 2468 additions and 4481 deletions

View File

@@ -1,5 +1,5 @@
[bumpversion]
current_version = 0.1.9
current_version = 0.1.10
commit = True
message = Bump version: {current_version} → {new_version}
tag = True

93
.github/workflows/docs_test.yml vendored Normal file
View File

@@ -0,0 +1,93 @@
name: Documentation Code Testing
on:
push:
branches:
- main
paths:
- docs/**
- .github/workflows/docs_test.yml
pull_request:
paths:
- docs/**
- .github/workflows/docs_test.yml
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
env:
# Disable full debug symbol generation to speed up CI build and keep memory down
# "1" means line tables only, which is useful for panic tracebacks.
RUSTFLAGS: "-C debuginfo=1"
RUST_BACKTRACE: "1"
jobs:
test-python:
name: Test doc python code
runs-on: ${{ matrix.os }}
strategy:
matrix:
python-minor-version: [ "11" ]
os: ["ubuntu-22.04"]
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: 3.${{ matrix.python-minor-version }}
cache: "pip"
cache-dependency-path: "docs/test/requirements.txt"
- name: Build Python
working-directory: docs/test
run:
python -m pip install -r requirements.txt
- name: Create test files
run: |
cd docs/test
python md_testing.py
- name: Test
run: |
cd docs/test/python
for d in *; do cd "$d"; echo "$d".py; python "$d".py; cd ..; done
test-node:
name: Test doc nodejs code
runs-on: ${{ matrix.os }}
strategy:
matrix:
node-version: [ "18" ]
os: ["ubuntu-22.04"]
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
lfs: true
- name: Set up Node
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- name: Install dependecies needed for ubuntu
if: ${{ matrix.os == 'ubuntu-22.04' }}
run: |
sudo apt install -y protobuf-compiler libssl-dev
- name: Install node dependencies
run: |
cd docs/test
npm install
- name: Rust cache
uses: swatinem/rust-cache@v2
- name: Install LanceDB
run: |
cd docs/test/node_modules/vectordb
npm ci
npm run build
npm run tsc
- name: Create test files
run: |
cd docs/test
node md_testing.js
- name: Test
run: |
cd docs/test/node
for d in *; do cd "$d"; echo "$d".js; node "$d".js; cd ..; done

2
.gitignore vendored
View File

@@ -3,6 +3,7 @@
*.egg-info
**/__pycache__
.DS_Store
venv
rust/target
rust/Cargo.lock
@@ -30,3 +31,4 @@ node/examples/**/dist
## Rust
target
Cargo.lock

View File

@@ -8,4 +8,14 @@ repos:
- repo: https://github.com/psf/black
rev: 22.12.0
hooks:
- id: black
- id: black
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.0.277
hooks:
- id: ruff
- repo: https://github.com/pycqa/isort
rev: 5.12.0
hooks:
- id: isort
name: isort (python)

3803
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,3 +4,11 @@ members = [
"rust/ffi/node"
]
resolver = "2"
[workspace.dependencies]
lance = "0.5.3"
arrow-array = "40.0"
arrow-data = "40.0"
arrow-schema = "40.0"
arrow-ipc = "40.0"
object_store = "0.6.1"

View File

@@ -65,7 +65,7 @@ pip install lancedb
```python
import lancedb
uri = "/tmp/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},

View File

@@ -38,6 +38,7 @@ plugins:
markdown_extensions:
- admonition
- footnotes
- pymdownx.superfences
- pymdownx.details
- pymdownx.highlight:
@@ -66,6 +67,7 @@ nav:
- YouTube Transcript Search: examples/youtube_transcript_bot_with_nodejs.md
- References:
- Vector Search: search.md
- SQL filters: sql.md
- Indexing: ann_indexes.md
- API references:
- Python API: python/python.md

View File

@@ -23,7 +23,7 @@ In the future we will look to automatically create and configure the ANN index.
# Create 10,000 sample vectors
data = [{"vector": row, "item": f"item {i}"}
for i, row in enumerate(np.random.random((10_000, 768)).astype('float32'))]
for i, row in enumerate(np.random.random((10_000, 1536)).astype('float32'))]
# Add the vectors to a table
tbl = db.create_table("my_vectors", data=data)
@@ -41,8 +41,8 @@ In the future we will look to automatically create and configure the ANN index.
for (let i = 0; i < 10_000; i++) {
data.push({vector: Array(1536).fill(i), id: `${i}`, content: "", longId: `${i}`},)
}
const table = await db.createTable('vectors', data)
await table.create_index({ type: 'ivf_pq', column: 'vector', num_partitions: 256, num_sub_vectors: 96 })
const table = await db.createTable('my_vectors', data)
await table.createIndex({ type: 'ivf_pq', column: 'vector', num_partitions: 256, num_sub_vectors: 96 })
```
Since `create_index` has a training step, it can take a few minutes to finish for large tables. You can control the index
@@ -73,12 +73,13 @@ There are a couple of parameters that can be used to fine-tune the search:
=== "Python"
```python
tbl.search(np.random.random((768))) \
tbl.search(np.random.random((1536))) \
.limit(2) \
.nprobes(20) \
.refine_factor(10) \
.to_df()
```
```
vector item score
0 [0.44949695, 0.8444449, 0.06281311, 0.23338133... item 1141 103.575333
1 [0.48587373, 0.269207, 0.15095535, 0.65531915,... item 3953 108.393867
@@ -86,8 +87,8 @@ There are a couple of parameters that can be used to fine-tune the search:
=== "Javascript"
```javascript
const results = await table
.search(Array(768).fill(1.2))
const results_1 = await table
.search(Array(1536).fill(1.2))
.limit(2)
.nprobes(20)
.refineFactor(10)
@@ -104,14 +105,14 @@ You can further filter the elements returned by a search using a where clause.
=== "Python"
```python
tbl.search(np.random.random((768))).where("item != 'item 1141'").to_df()
tbl.search(np.random.random((1536))).where("item != 'item 1141'").to_df()
```
=== "Javascript"
```javascript
const results = await table
const results_2 = await table
.search(Array(1536).fill(1.2))
.where("item != 'item 1141'")
.where("id != '1141'")
.execute()
```
@@ -121,7 +122,9 @@ You can select the columns returned by the query using a select clause.
=== "Python"
```python
tbl.search(np.random.random((768))).select(["vector"]).to_df()
tbl.search(np.random.random((1536))).select(["vector"]).to_df()
```
```
vector score
0 [0.30928212, 0.022668175, 0.1756372, 0.4911822... 93.971092
1 [0.2525465, 0.01723831, 0.261568, 0.002007689,... 95.173485
@@ -130,7 +133,7 @@ You can select the columns returned by the query using a select clause.
=== "Javascript"
```javascript
const results = await table
const results_3 = await table
.search(Array(1536).fill(1.2))
.select(["id"])
.execute()

View File

@@ -23,7 +23,7 @@ We'll cover the basics of using LanceDB on your local machine in this section.
=== "Python"
```python
import lancedb
uri = "~/.lancedb"
uri = "data/sample-lancedb"
db = lancedb.connect(uri)
```
@@ -35,7 +35,7 @@ We'll cover the basics of using LanceDB on your local machine in this section.
```javascript
const lancedb = require("vectordb");
const uri = "~./lancedb";
const uri = "data/sample-lancedb";
const db = await lancedb.connect(uri);
```
@@ -102,7 +102,7 @@ Once created, you can open a table using the following code:
If you forget the name of your table, you can always get a listing of all table names:
```javascript
console.log(db.tableNames());
console.log(await db.tableNames());
```
## How to add data to a table
@@ -118,7 +118,7 @@ After a table has been created, you can always add more data to it using
=== "Javascript"
```javascript
await tbl.add([vector: [1.3, 1.4], item: "fizz", price: 100.0},
await tbl.add([{vector: [1.3, 1.4], item: "fizz", price: 100.0},
{vector: [9.5, 56.2], item: "buzz", price: 200.0}])
```

View File

@@ -98,7 +98,7 @@ You can also use an external API like OpenAI to generate embeddings
embededings for your data.
```javascript
const db = await lancedb.connect("/tmp/lancedb");
const db = await lancedb.connect("data/sample-lancedb");
const data = [
{ text: 'pepperoni' },
{ text: 'pineapple' }

View File

@@ -79,10 +79,7 @@ def qanda_langchain(query):
download_docs()
docs = store_docs()
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=200,
)
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200,)
documents = text_splitter.split_documents(docs)
embeddings = OpenAIEmbeddings()

View File

@@ -18,6 +18,20 @@ Assume:
1. `table` is a LanceDB Table
2. `text` is the name of the Table column that we want to index
For example,
```python
import lancedb
uri = "data/sample-lancedb"
db = lancedb.connect(uri)
table = db.create_table("my_table",
data=[{"vector": [3.1, 4.1], "text": "Frodo was a happy puppy"},
{"vector": [5.9, 26.5], "text": "There are several kittens playing"}])
```
To create the index:
```python

View File

@@ -28,7 +28,7 @@ LanceDB's core is written in Rust 🦀 and is built using <a href="https://githu
```python
import lancedb
uri = "/tmp/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},
@@ -44,7 +44,7 @@ LanceDB's core is written in Rust 🦀 and is built using <a href="https://githu
```javascript
const lancedb = require("vectordb");
const uri = "/tmp/lancedb";
const uri = "data/sample-lancedb";
const db = await lancedb.connect(uri);
const table = await db.createTable("my_table",
[{ id: 1, vector: [3.1, 4.1], item: "foo", price: 10.0 },

View File

@@ -6,11 +6,11 @@ Built on top of Apache Arrow, `LanceDB` is easy to integrate with the Python eco
First, we need to connect to a `LanceDB` database.
``` py
```py
import lancedb
db = lancedb.connect("/tmp/lancedb")
db = lancedb.connect("data/sample-lancedb")
```
And write a `Pandas DataFrame` to LanceDB directly.
@@ -79,7 +79,7 @@ We will re-use the dataset created previously
```python
import lancedb
db = lancedb.connect("/tmp/lancedb")
db = lancedb.connect("data/sample-lancedb")
table = db.open_table("pd_table")
arrow_table = table.to_arrow()
```
@@ -87,8 +87,12 @@ arrow_table = table.to_arrow()
`DuckDB` can directly query the `arrow_table`:
```python
In [15]: duckdb.query("SELECT * FROM t")
Out[15]:
import duckdb
duckdb.query("SELECT * FROM arrow_table")
```
```
┌─────────────┬─────────┬────────┐
│ vector │ item │ price │
│ float[] │ varchar │ double │
@@ -96,8 +100,12 @@ Out[15]:
│ [3.1, 4.1] │ foo │ 10.0 │
│ [5.9, 26.5] │ bar │ 20.0 │
└─────────────┴─────────┴────────┘
```
```python
duckdb.query("SELECT mean(price) FROM arrow_table")
```
In [16]: duckdb.query("SELECT mean(price) FROM t")
```
Out[16]:
┌─────────────┐
│ mean(price) │

View File

@@ -16,9 +16,11 @@ npm install vectordb
```javascript
const lancedb = require('vectordb');
const db = lancedb.connect('<PATH_TO_LANCEDB_DATASET>');
const table = await db.openTable('my_table');
const query = await table.search([0.1, 0.3]).setLimit(20).execute();
const db = await lancedb.connect('data/sample-lancedb');
const table = await db.createTable("my_table",
[{ id: 1, vector: [0.1, 1.0], item: "foo", price: 10.0 },
{ id: 2, vector: [3.9, 0.5], item: "bar", price: 20.0 }])
const results = await table.search([0.1, 0.3]).limit(20).execute();
console.log(results);
```
@@ -26,12 +28,6 @@ The [examples](./examples) folder contains complete examples.
## Development
The LanceDB javascript is built with npm:
```bash
npm run tsc
```
Run the tests with
```bash

View File

@@ -1,211 +0,0 @@
[vectordb](../README.md) / [Exports](../modules.md) / Connection
# Class: Connection
A connection to a LanceDB database.
## Table of contents
### Constructors
- [constructor](Connection.md#constructor)
### Properties
- [\_db](Connection.md#_db)
- [\_uri](Connection.md#_uri)
### Accessors
- [uri](Connection.md#uri)
### Methods
- [createTable](Connection.md#createtable)
- [createTableArrow](Connection.md#createtablearrow)
- [openTable](Connection.md#opentable)
- [tableNames](Connection.md#tablenames)
## Constructors
### constructor
**new Connection**(`db`, `uri`)
#### Parameters
| Name | Type |
| :------ | :------ |
| `db` | `any` |
| `uri` | `string` |
#### Defined in
[index.ts:46](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L46)
## Properties
### \_db
`Private` `Readonly` **\_db**: `any`
#### Defined in
[index.ts:44](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L44)
___
### \_uri
`Private` `Readonly` **\_uri**: `string`
#### Defined in
[index.ts:43](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L43)
## Accessors
### uri
`get` **uri**(): `string`
#### Returns
`string`
#### Defined in
[index.ts:51](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L51)
## Methods
### createTable
**createTable**(`name`, `data`): `Promise`<[`Table`](Table.md)<`number`[]\>\>
Creates a new Table and initialize it with new data.
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `name` | `string` | The name of the table. |
| `data` | `Record`<`string`, `unknown`\>[] | Non-empty Array of Records to be inserted into the Table |
#### Returns
`Promise`<[`Table`](Table.md)<`number`[]\>\>
#### Defined in
[index.ts:91](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L91)
**createTable**<`T`\>(`name`, `data`, `embeddings`): `Promise`<[`Table`](Table.md)<`T`\>\>
Creates a new Table and initialize it with new data.
#### Type parameters
| Name |
| :------ |
| `T` |
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `name` | `string` | The name of the table. |
| `data` | `Record`<`string`, `unknown`\>[] | Non-empty Array of Records to be inserted into the Table |
| `embeddings` | [`EmbeddingFunction`](../interfaces/EmbeddingFunction.md)<`T`\> | An embedding function to use on this Table |
#### Returns
`Promise`<[`Table`](Table.md)<`T`\>\>
#### Defined in
[index.ts:99](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L99)
___
### createTableArrow
**createTableArrow**(`name`, `table`): `Promise`<[`Table`](Table.md)<`number`[]\>\>
#### Parameters
| Name | Type |
| :------ | :------ |
| `name` | `string` |
| `table` | `Table`<`any`\> |
#### Returns
`Promise`<[`Table`](Table.md)<`number`[]\>\>
#### Defined in
[index.ts:109](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L109)
___
### openTable
**openTable**(`name`): `Promise`<[`Table`](Table.md)<`number`[]\>\>
Open a table in the database.
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `name` | `string` | The name of the table. |
#### Returns
`Promise`<[`Table`](Table.md)<`number`[]\>\>
#### Defined in
[index.ts:67](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L67)
**openTable**<`T`\>(`name`, `embeddings`): `Promise`<[`Table`](Table.md)<`T`\>\>
Open a table in the database.
#### Type parameters
| Name |
| :------ |
| `T` |
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `name` | `string` | The name of the table. |
| `embeddings` | [`EmbeddingFunction`](../interfaces/EmbeddingFunction.md)<`T`\> | An embedding function to use on this Table |
#### Returns
`Promise`<[`Table`](Table.md)<`T`\>\>
#### Defined in
[index.ts:74](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L74)
___
### tableNames
**tableNames**(): `Promise`<`string`[]\>
Get the names of all tables in the database.
#### Returns
`Promise`<`string`[]\>
#### Defined in
[index.ts:58](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L58)

View File

@@ -0,0 +1,294 @@
[vectordb](../README.md) / [Exports](../modules.md) / LocalConnection
# Class: LocalConnection
A connection to a LanceDB database.
## Implements
- [`Connection`](../interfaces/Connection.md)
## Table of contents
### Constructors
- [constructor](LocalConnection.md#constructor)
### Properties
- [\_db](LocalConnection.md#_db)
- [\_uri](LocalConnection.md#_uri)
### Accessors
- [uri](LocalConnection.md#uri)
### Methods
- [createTable](LocalConnection.md#createtable)
- [createTableArrow](LocalConnection.md#createtablearrow)
- [dropTable](LocalConnection.md#droptable)
- [openTable](LocalConnection.md#opentable)
- [tableNames](LocalConnection.md#tablenames)
## Constructors
### constructor
**new LocalConnection**(`db`, `uri`)
#### Parameters
| Name | Type |
| :------ | :------ |
| `db` | `any` |
| `uri` | `string` |
#### Defined in
[index.ts:132](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L132)
## Properties
### \_db
`Private` `Readonly` **\_db**: `any`
#### Defined in
[index.ts:130](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L130)
___
### \_uri
`Private` `Readonly` **\_uri**: `string`
#### Defined in
[index.ts:129](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L129)
## Accessors
### uri
`get` **uri**(): `string`
#### Returns
`string`
#### Implementation of
[Connection](../interfaces/Connection.md).[uri](../interfaces/Connection.md#uri)
#### Defined in
[index.ts:137](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L137)
## Methods
### createTable
**createTable**(`name`, `data`, `mode?`): `Promise`<[`Table`](../interfaces/Table.md)<`number`[]\>\>
Creates a new Table and initialize it with new data.
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `name` | `string` | The name of the table. |
| `data` | `Record`<`string`, `unknown`\>[] | Non-empty Array of Records to be inserted into the Table |
| `mode?` | [`WriteMode`](../enums/WriteMode.md) | The write mode to use when creating the table. |
#### Returns
`Promise`<[`Table`](../interfaces/Table.md)<`number`[]\>\>
#### Implementation of
[Connection](../interfaces/Connection.md).[createTable](../interfaces/Connection.md#createtable)
#### Defined in
[index.ts:177](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L177)
**createTable**(`name`, `data`, `mode`): `Promise`<[`Table`](../interfaces/Table.md)<`number`[]\>\>
#### Parameters
| Name | Type |
| :------ | :------ |
| `name` | `string` |
| `data` | `Record`<`string`, `unknown`\>[] |
| `mode` | [`WriteMode`](../enums/WriteMode.md) |
#### Returns
`Promise`<[`Table`](../interfaces/Table.md)<`number`[]\>\>
#### Implementation of
Connection.createTable
#### Defined in
[index.ts:178](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L178)
**createTable**<`T`\>(`name`, `data`, `mode`, `embeddings`): `Promise`<[`Table`](../interfaces/Table.md)<`T`\>\>
Creates a new Table and initialize it with new data.
#### Type parameters
| Name |
| :------ |
| `T` |
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `name` | `string` | The name of the table. |
| `data` | `Record`<`string`, `unknown`\>[] | Non-empty Array of Records to be inserted into the Table |
| `mode` | [`WriteMode`](../enums/WriteMode.md) | The write mode to use when creating the table. |
| `embeddings` | [`EmbeddingFunction`](../interfaces/EmbeddingFunction.md)<`T`\> | An embedding function to use on this Table |
#### Returns
`Promise`<[`Table`](../interfaces/Table.md)<`T`\>\>
#### Implementation of
Connection.createTable
#### Defined in
[index.ts:188](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L188)
___
### createTableArrow
**createTableArrow**(`name`, `table`): `Promise`<[`Table`](../interfaces/Table.md)<`number`[]\>\>
#### Parameters
| Name | Type |
| :------ | :------ |
| `name` | `string` |
| `table` | `Table`<`any`\> |
#### Returns
`Promise`<[`Table`](../interfaces/Table.md)<`number`[]\>\>
#### Implementation of
[Connection](../interfaces/Connection.md).[createTableArrow](../interfaces/Connection.md#createtablearrow)
#### Defined in
[index.ts:201](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L201)
___
### dropTable
**dropTable**(`name`): `Promise`<`void`\>
Drop an existing table.
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `name` | `string` | The name of the table to drop. |
#### Returns
`Promise`<`void`\>
#### Implementation of
[Connection](../interfaces/Connection.md).[dropTable](../interfaces/Connection.md#droptable)
#### Defined in
[index.ts:211](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L211)
___
### openTable
**openTable**(`name`): `Promise`<[`Table`](../interfaces/Table.md)<`number`[]\>\>
Open a table in the database.
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `name` | `string` | The name of the table. |
#### Returns
`Promise`<[`Table`](../interfaces/Table.md)<`number`[]\>\>
#### Implementation of
[Connection](../interfaces/Connection.md).[openTable](../interfaces/Connection.md#opentable)
#### Defined in
[index.ts:153](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L153)
**openTable**<`T`\>(`name`, `embeddings`): `Promise`<[`Table`](../interfaces/Table.md)<`T`\>\>
Open a table in the database.
#### Type parameters
| Name |
| :------ |
| `T` |
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `name` | `string` | The name of the table. |
| `embeddings` | [`EmbeddingFunction`](../interfaces/EmbeddingFunction.md)<`T`\> | An embedding function to use on this Table |
#### Returns
`Promise`<[`Table`](../interfaces/Table.md)<`T`\>\>
#### Implementation of
Connection.openTable
#### Defined in
[index.ts:160](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L160)
___
### tableNames
**tableNames**(): `Promise`<`string`[]\>
Get the names of all tables in the database.
#### Returns
`Promise`<`string`[]\>
#### Implementation of
[Connection](../interfaces/Connection.md).[tableNames](../interfaces/Connection.md#tablenames)
#### Defined in
[index.ts:144](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L144)

View File

@@ -0,0 +1,289 @@
[vectordb](../README.md) / [Exports](../modules.md) / LocalTable
# Class: LocalTable<T\>
A LanceDB Table is the collection of Records. Each Record has one or more vector fields.
## Type parameters
| Name | Type |
| :------ | :------ |
| `T` | `number`[] |
## Implements
- [`Table`](../interfaces/Table.md)<`T`\>
## Table of contents
### Constructors
- [constructor](LocalTable.md#constructor)
### Properties
- [\_embeddings](LocalTable.md#_embeddings)
- [\_name](LocalTable.md#_name)
- [\_tbl](LocalTable.md#_tbl)
### Accessors
- [name](LocalTable.md#name)
### Methods
- [add](LocalTable.md#add)
- [countRows](LocalTable.md#countrows)
- [createIndex](LocalTable.md#createindex)
- [delete](LocalTable.md#delete)
- [overwrite](LocalTable.md#overwrite)
- [search](LocalTable.md#search)
## Constructors
### constructor
**new LocalTable**<`T`\>(`tbl`, `name`)
#### Type parameters
| Name | Type |
| :------ | :------ |
| `T` | `number`[] |
#### Parameters
| Name | Type |
| :------ | :------ |
| `tbl` | `any` |
| `name` | `string` |
#### Defined in
[index.ts:221](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L221)
**new LocalTable**<`T`\>(`tbl`, `name`, `embeddings`)
#### Type parameters
| Name | Type |
| :------ | :------ |
| `T` | `number`[] |
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `tbl` | `any` | |
| `name` | `string` | |
| `embeddings` | [`EmbeddingFunction`](../interfaces/EmbeddingFunction.md)<`T`\> | An embedding function to use when interacting with this table |
#### Defined in
[index.ts:227](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L227)
## Properties
### \_embeddings
`Private` `Optional` `Readonly` **\_embeddings**: [`EmbeddingFunction`](../interfaces/EmbeddingFunction.md)<`T`\>
#### Defined in
[index.ts:219](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L219)
___
### \_name
`Private` `Readonly` **\_name**: `string`
#### Defined in
[index.ts:218](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L218)
___
### \_tbl
`Private` `Readonly` **\_tbl**: `any`
#### Defined in
[index.ts:217](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L217)
## Accessors
### name
`get` **name**(): `string`
#### Returns
`string`
#### Implementation of
[Table](../interfaces/Table.md).[name](../interfaces/Table.md#name)
#### Defined in
[index.ts:234](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L234)
## Methods
### add
**add**(`data`): `Promise`<`number`\>
Insert records into this Table.
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `data` | `Record`<`string`, `unknown`\>[] | Records to be inserted into the Table |
#### Returns
`Promise`<`number`\>
The number of rows added to the table
#### Implementation of
[Table](../interfaces/Table.md).[add](../interfaces/Table.md#add)
#### Defined in
[index.ts:252](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L252)
___
### countRows
**countRows**(): `Promise`<`number`\>
Returns the number of rows in this table.
#### Returns
`Promise`<`number`\>
#### Implementation of
[Table](../interfaces/Table.md).[countRows](../interfaces/Table.md#countrows)
#### Defined in
[index.ts:278](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L278)
___
### createIndex
**createIndex**(`indexParams`): `Promise`<`any`\>
Create an ANN index on this Table vector index.
**`See`**
VectorIndexParams.
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `indexParams` | `IvfPQIndexConfig` | The parameters of this Index, |
#### Returns
`Promise`<`any`\>
#### Implementation of
[Table](../interfaces/Table.md).[createIndex](../interfaces/Table.md#createindex)
#### Defined in
[index.ts:271](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L271)
___
### delete
**delete**(`filter`): `Promise`<`void`\>
Delete rows from this table.
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `filter` | `string` | A filter in the same format used by a sql WHERE clause. |
#### Returns
`Promise`<`void`\>
#### Implementation of
[Table](../interfaces/Table.md).[delete](../interfaces/Table.md#delete)
#### Defined in
[index.ts:287](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L287)
___
### overwrite
**overwrite**(`data`): `Promise`<`number`\>
Insert records into this Table, replacing its contents.
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `data` | `Record`<`string`, `unknown`\>[] | Records to be inserted into the Table |
#### Returns
`Promise`<`number`\>
The number of rows added to the table
#### Implementation of
[Table](../interfaces/Table.md).[overwrite](../interfaces/Table.md#overwrite)
#### Defined in
[index.ts:262](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L262)
___
### search
**search**(`query`): [`Query`](Query.md)<`T`\>
Creates a search query to find the nearest neighbors of the given search term
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `query` | `T` | The query search term |
#### Returns
[`Query`](Query.md)<`T`\>
#### Implementation of
[Table](../interfaces/Table.md).[search](../interfaces/Table.md#search)
#### Defined in
[index.ts:242](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L242)

View File

@@ -40,7 +40,7 @@ An embedding function that automatically creates vector representation for a giv
#### Defined in
[embedding/openai.ts:21](https://github.com/lancedb/lancedb/blob/31dab97/node/src/embedding/openai.ts#L21)
[embedding/openai.ts:21](https://github.com/lancedb/lancedb/blob/7247834/node/src/embedding/openai.ts#L21)
## Properties
@@ -50,7 +50,7 @@ An embedding function that automatically creates vector representation for a giv
#### Defined in
[embedding/openai.ts:19](https://github.com/lancedb/lancedb/blob/31dab97/node/src/embedding/openai.ts#L19)
[embedding/openai.ts:19](https://github.com/lancedb/lancedb/blob/7247834/node/src/embedding/openai.ts#L19)
___
@@ -60,7 +60,7 @@ ___
#### Defined in
[embedding/openai.ts:18](https://github.com/lancedb/lancedb/blob/31dab97/node/src/embedding/openai.ts#L18)
[embedding/openai.ts:18](https://github.com/lancedb/lancedb/blob/7247834/node/src/embedding/openai.ts#L18)
___
@@ -76,7 +76,7 @@ The name of the column that will be used as input for the Embedding Function.
#### Defined in
[embedding/openai.ts:50](https://github.com/lancedb/lancedb/blob/31dab97/node/src/embedding/openai.ts#L50)
[embedding/openai.ts:50](https://github.com/lancedb/lancedb/blob/7247834/node/src/embedding/openai.ts#L50)
## Methods
@@ -102,4 +102,4 @@ Creates a vector representation for the given values.
#### Defined in
[embedding/openai.ts:38](https://github.com/lancedb/lancedb/blob/31dab97/node/src/embedding/openai.ts#L38)
[embedding/openai.ts:38](https://github.com/lancedb/lancedb/blob/7247834/node/src/embedding/openai.ts#L38)

View File

@@ -18,7 +18,6 @@ A builder for nearest neighbor queries for LanceDB.
### Properties
- [\_columns](Query.md#_columns)
- [\_embeddings](Query.md#_embeddings)
- [\_filter](Query.md#_filter)
- [\_limit](Query.md#_limit)
@@ -27,7 +26,9 @@ A builder for nearest neighbor queries for LanceDB.
- [\_query](Query.md#_query)
- [\_queryVector](Query.md#_queryvector)
- [\_refineFactor](Query.md#_refinefactor)
- [\_select](Query.md#_select)
- [\_tbl](Query.md#_tbl)
- [where](Query.md#where)
### Methods
@@ -37,6 +38,7 @@ A builder for nearest neighbor queries for LanceDB.
- [metricType](Query.md#metrictype)
- [nprobes](Query.md#nprobes)
- [refineFactor](Query.md#refinefactor)
- [select](Query.md#select)
## Constructors
@@ -60,27 +62,17 @@ A builder for nearest neighbor queries for LanceDB.
#### Defined in
[index.ts:241](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L241)
[index.ts:362](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L362)
## Properties
### \_columns
`Private` `Optional` `Readonly` **\_columns**: `string`[]
#### Defined in
[index.ts:236](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L236)
___
### \_embeddings
`Private` `Optional` `Readonly` **\_embeddings**: [`EmbeddingFunction`](../interfaces/EmbeddingFunction.md)<`T`\>
#### Defined in
[index.ts:239](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L239)
[index.ts:360](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L360)
___
@@ -90,7 +82,7 @@ ___
#### Defined in
[index.ts:237](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L237)
[index.ts:358](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L358)
___
@@ -100,7 +92,7 @@ ___
#### Defined in
[index.ts:233](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L233)
[index.ts:354](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L354)
___
@@ -110,7 +102,7 @@ ___
#### Defined in
[index.ts:238](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L238)
[index.ts:359](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L359)
___
@@ -120,7 +112,7 @@ ___
#### Defined in
[index.ts:235](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L235)
[index.ts:356](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L356)
___
@@ -130,7 +122,7 @@ ___
#### Defined in
[index.ts:231](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L231)
[index.ts:352](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L352)
___
@@ -140,7 +132,7 @@ ___
#### Defined in
[index.ts:232](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L232)
[index.ts:353](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L353)
___
@@ -150,7 +142,17 @@ ___
#### Defined in
[index.ts:234](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L234)
[index.ts:355](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L355)
___
### \_select
`Private` `Optional` **\_select**: `string`[]
#### Defined in
[index.ts:357](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L357)
___
@@ -160,7 +162,33 @@ ___
#### Defined in
[index.ts:230](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L230)
[index.ts:351](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L351)
___
### where
**where**: (`value`: `string`) => [`Query`](Query.md)<`T`\>
#### Type declaration
▸ (`value`): [`Query`](Query.md)<`T`\>
A filter statement to be applied to this query.
##### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `value` | `string` | A filter in the same format used by a sql WHERE clause. |
##### Returns
[`Query`](Query.md)<`T`\>
#### Defined in
[index.ts:410](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L410)
## Methods
@@ -182,7 +210,7 @@ Execute the query and return the results as an Array of Objects
#### Defined in
[index.ts:301](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L301)
[index.ts:433](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L433)
___
@@ -204,7 +232,7 @@ A filter statement to be applied to this query.
#### Defined in
[index.ts:284](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L284)
[index.ts:405](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L405)
___
@@ -226,7 +254,7 @@ Sets the number of results that will be returned
#### Defined in
[index.ts:257](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L257)
[index.ts:378](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L378)
___
@@ -252,7 +280,7 @@ MetricType for the different options
#### Defined in
[index.ts:293](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L293)
[index.ts:425](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L425)
___
@@ -274,7 +302,7 @@ The number of probes used. A higher number makes search more accurate but also s
#### Defined in
[index.ts:275](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L275)
[index.ts:396](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L396)
___
@@ -296,4 +324,26 @@ Refine the results by reading extra elements and re-ranking them in memory.
#### Defined in
[index.ts:266](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L266)
[index.ts:387](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L387)
___
### select
**select**(`value`): [`Query`](Query.md)<`T`\>
Return only the specified columns.
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `value` | `string`[] | Only select the specified columns. If not specified, all columns will be returned. |
#### Returns
[`Query`](Query.md)<`T`\>
#### Defined in
[index.ts:416](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L416)

View File

@@ -1,215 +0,0 @@
[vectordb](../README.md) / [Exports](../modules.md) / Table
# Class: Table<T\>
## Type parameters
| Name | Type |
| :------ | :------ |
| `T` | `number`[] |
## Table of contents
### Constructors
- [constructor](Table.md#constructor)
### Properties
- [\_embeddings](Table.md#_embeddings)
- [\_name](Table.md#_name)
- [\_tbl](Table.md#_tbl)
### Accessors
- [name](Table.md#name)
### Methods
- [add](Table.md#add)
- [create\_index](Table.md#create_index)
- [overwrite](Table.md#overwrite)
- [search](Table.md#search)
## Constructors
### constructor
**new Table**<`T`\>(`tbl`, `name`)
#### Type parameters
| Name | Type |
| :------ | :------ |
| `T` | `number`[] |
#### Parameters
| Name | Type |
| :------ | :------ |
| `tbl` | `any` |
| `name` | `string` |
#### Defined in
[index.ts:121](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L121)
**new Table**<`T`\>(`tbl`, `name`, `embeddings`)
#### Type parameters
| Name | Type |
| :------ | :------ |
| `T` | `number`[] |
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `tbl` | `any` | |
| `name` | `string` | |
| `embeddings` | [`EmbeddingFunction`](../interfaces/EmbeddingFunction.md)<`T`\> | An embedding function to use when interacting with this table |
#### Defined in
[index.ts:127](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L127)
## Properties
### \_embeddings
`Private` `Optional` `Readonly` **\_embeddings**: [`EmbeddingFunction`](../interfaces/EmbeddingFunction.md)<`T`\>
#### Defined in
[index.ts:119](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L119)
___
### \_name
`Private` `Readonly` **\_name**: `string`
#### Defined in
[index.ts:118](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L118)
___
### \_tbl
`Private` `Readonly` **\_tbl**: `any`
#### Defined in
[index.ts:117](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L117)
## Accessors
### name
`get` **name**(): `string`
#### Returns
`string`
#### Defined in
[index.ts:134](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L134)
## Methods
### add
**add**(`data`): `Promise`<`number`\>
Insert records into this Table.
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `data` | `Record`<`string`, `unknown`\>[] | Records to be inserted into the Table |
#### Returns
`Promise`<`number`\>
The number of rows added to the table
#### Defined in
[index.ts:152](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L152)
___
### create\_index
**create_index**(`indexParams`): `Promise`<`any`\>
Create an ANN index on this Table vector index.
**`See`**
VectorIndexParams.
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `indexParams` | `IvfPQIndexConfig` | The parameters of this Index, |
#### Returns
`Promise`<`any`\>
#### Defined in
[index.ts:171](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L171)
___
### overwrite
**overwrite**(`data`): `Promise`<`number`\>
Insert records into this Table, replacing its contents.
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `data` | `Record`<`string`, `unknown`\>[] | Records to be inserted into the Table |
#### Returns
`Promise`<`number`\>
The number of rows added to the table
#### Defined in
[index.ts:162](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L162)
___
### search
**search**(`query`): [`Query`](Query.md)<`T`\>
Creates a search query to find the nearest neighbors of the given search term
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `query` | `T` | The query search term |
#### Returns
[`Query`](Query.md)<`T`\>
#### Defined in
[index.ts:142](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L142)

View File

@@ -9,6 +9,7 @@ Distance metrics type.
### Enumeration Members
- [Cosine](MetricType.md#cosine)
- [Dot](MetricType.md#dot)
- [L2](MetricType.md#l2)
## Enumeration Members
@@ -21,7 +22,19 @@ Cosine distance
#### Defined in
[index.ts:341](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L341)
[index.ts:481](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L481)
___
### Dot
• **Dot** = ``"dot"``
Dot product
#### Defined in
[index.ts:486](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L486)
___
@@ -33,4 +46,4 @@ Euclidean distance
#### Defined in
[index.ts:336](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L336)
[index.ts:476](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L476)

View File

@@ -2,11 +2,14 @@
# Enumeration: WriteMode
Write mode for writing a table.
## Table of contents
### Enumeration Members
- [Append](WriteMode.md#append)
- [Create](WriteMode.md#create)
- [Overwrite](WriteMode.md#overwrite)
## Enumeration Members
@@ -15,9 +18,23 @@
**Append** = ``"append"``
Append new data to the table.
#### Defined in
[index.ts:326](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L326)
[index.ts:466](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L466)
___
### Create
• **Create** = ``"create"``
Create a new [Table](../interfaces/Table.md).
#### Defined in
[index.ts:462](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L462)
___
@@ -25,6 +42,8 @@ ___
• **Overwrite** = ``"overwrite"``
Overwrite the existing [Table](../interfaces/Table.md) if presented.
#### Defined in
[index.ts:325](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L325)
[index.ts:464](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L464)

View File

@@ -0,0 +1,152 @@
[vectordb](../README.md) / [Exports](../modules.md) / Connection
# Interface: Connection
A LanceDB Connection that allows you to open tables and create new ones.
Connection could be local against filesystem or remote against a server.
## Implemented by
- [`LocalConnection`](../classes/LocalConnection.md)
## Table of contents
### Properties
- [uri](Connection.md#uri)
### Methods
- [createTable](Connection.md#createtable)
- [createTableArrow](Connection.md#createtablearrow)
- [dropTable](Connection.md#droptable)
- [openTable](Connection.md#opentable)
- [tableNames](Connection.md#tablenames)
## Properties
### uri
**uri**: `string`
#### Defined in
[index.ts:45](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L45)
## Methods
### createTable
**createTable**<`T`\>(`name`, `data`, `mode?`, `embeddings?`): `Promise`<[`Table`](Table.md)<`T`\>\>
Creates a new Table and initialize it with new data.
#### Type parameters
| Name |
| :------ |
| `T` |
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `name` | `string` | The name of the table. |
| `data` | `Record`<`string`, `unknown`\>[] | Non-empty Array of Records to be inserted into the table |
| `mode?` | [`WriteMode`](../enums/WriteMode.md) | The write mode to use when creating the table. |
| `embeddings?` | [`EmbeddingFunction`](EmbeddingFunction.md)<`T`\> | An embedding function to use on this table |
#### Returns
`Promise`<[`Table`](Table.md)<`T`\>\>
#### Defined in
[index.ts:65](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L65)
___
### createTableArrow
**createTableArrow**(`name`, `table`): `Promise`<[`Table`](Table.md)<`number`[]\>\>
#### Parameters
| Name | Type |
| :------ | :------ |
| `name` | `string` |
| `table` | `Table`<`any`\> |
#### Returns
`Promise`<[`Table`](Table.md)<`number`[]\>\>
#### Defined in
[index.ts:67](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L67)
___
### dropTable
**dropTable**(`name`): `Promise`<`void`\>
Drop an existing table.
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `name` | `string` | The name of the table to drop. |
#### Returns
`Promise`<`void`\>
#### Defined in
[index.ts:73](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L73)
___
### openTable
**openTable**<`T`\>(`name`, `embeddings?`): `Promise`<[`Table`](Table.md)<`T`\>\>
Open a table in the database.
#### Type parameters
| Name |
| :------ |
| `T` |
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `name` | `string` | The name of the table. |
| `embeddings?` | [`EmbeddingFunction`](EmbeddingFunction.md)<`T`\> | An embedding function to use on this table |
#### Returns
`Promise`<[`Table`](Table.md)<`T`\>\>
#### Defined in
[index.ts:55](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L55)
___
### tableNames
**tableNames**(): `Promise`<`string`[]\>
#### Returns
`Promise`<`string`[]\>
#### Defined in
[index.ts:47](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L47)

View File

@@ -45,7 +45,7 @@ Creates a vector representation for the given values.
#### Defined in
[embedding/embedding_function.ts:27](https://github.com/lancedb/lancedb/blob/31dab97/node/src/embedding/embedding_function.ts#L27)
[embedding/embedding_function.ts:27](https://github.com/lancedb/lancedb/blob/7247834/node/src/embedding/embedding_function.ts#L27)
___
@@ -57,4 +57,4 @@ The name of the column that will be used as input for the Embedding Function.
#### Defined in
[embedding/embedding_function.ts:22](https://github.com/lancedb/lancedb/blob/31dab97/node/src/embedding/embedding_function.ts#L22)
[embedding/embedding_function.ts:22](https://github.com/lancedb/lancedb/blob/7247834/node/src/embedding/embedding_function.ts#L22)

View File

@@ -0,0 +1,195 @@
[vectordb](../README.md) / [Exports](../modules.md) / Table
# Interface: Table<T\>
A LanceDB Table is the collection of Records. Each Record has one or more vector fields.
## Type parameters
| Name | Type |
| :------ | :------ |
| `T` | `number`[] |
## Implemented by
- [`LocalTable`](../classes/LocalTable.md)
## Table of contents
### Properties
- [add](Table.md#add)
- [countRows](Table.md#countrows)
- [createIndex](Table.md#createindex)
- [delete](Table.md#delete)
- [name](Table.md#name)
- [overwrite](Table.md#overwrite)
- [search](Table.md#search)
## Properties
### add
**add**: (`data`: `Record`<`string`, `unknown`\>[]) => `Promise`<`number`\>
#### Type declaration
▸ (`data`): `Promise`<`number`\>
Insert records into this Table.
##### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `data` | `Record`<`string`, `unknown`\>[] | Records to be inserted into the Table |
##### Returns
`Promise`<`number`\>
The number of rows added to the table
#### Defined in
[index.ts:95](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L95)
___
### countRows
**countRows**: () => `Promise`<`number`\>
#### Type declaration
▸ (): `Promise`<`number`\>
Returns the number of rows in this table.
##### Returns
`Promise`<`number`\>
#### Defined in
[index.ts:115](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L115)
___
### createIndex
**createIndex**: (`indexParams`: `IvfPQIndexConfig`) => `Promise`<`any`\>
#### Type declaration
▸ (`indexParams`): `Promise`<`any`\>
Create an ANN index on this Table vector index.
**`See`**
VectorIndexParams.
##### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `indexParams` | `IvfPQIndexConfig` | The parameters of this Index, |
##### Returns
`Promise`<`any`\>
#### Defined in
[index.ts:110](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L110)
___
### delete
**delete**: (`filter`: `string`) => `Promise`<`void`\>
#### Type declaration
▸ (`filter`): `Promise`<`void`\>
Delete rows from this table.
##### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `filter` | `string` | A filter in the same format used by a sql WHERE clause. |
##### Returns
`Promise`<`void`\>
#### Defined in
[index.ts:122](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L122)
___
### name
**name**: `string`
#### Defined in
[index.ts:81](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L81)
___
### overwrite
**overwrite**: (`data`: `Record`<`string`, `unknown`\>[]) => `Promise`<`number`\>
#### Type declaration
▸ (`data`): `Promise`<`number`\>
Insert records into this Table, replacing its contents.
##### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `data` | `Record`<`string`, `unknown`\>[] | Records to be inserted into the Table |
##### Returns
`Promise`<`number`\>
The number of rows added to the table
#### Defined in
[index.ts:103](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L103)
___
### search
**search**: (`query`: `T`) => [`Query`](../classes/Query.md)<`T`\>
#### Type declaration
▸ (`query`): [`Query`](../classes/Query.md)<`T`\>
Creates a search query to find the nearest neighbors of the given search term
##### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `query` | `T` | The query search term |
##### Returns
[`Query`](../classes/Query.md)<`T`\>
#### Defined in
[index.ts:87](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L87)

View File

@@ -11,14 +11,16 @@
### Classes
- [Connection](classes/Connection.md)
- [LocalConnection](classes/LocalConnection.md)
- [LocalTable](classes/LocalTable.md)
- [OpenAIEmbeddingFunction](classes/OpenAIEmbeddingFunction.md)
- [Query](classes/Query.md)
- [Table](classes/Table.md)
### Interfaces
- [Connection](interfaces/Connection.md)
- [EmbeddingFunction](interfaces/EmbeddingFunction.md)
- [Table](interfaces/Table.md)
### Type Aliases
@@ -36,13 +38,13 @@
#### Defined in
[index.ts:224](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L224)
[index.ts:345](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L345)
## Functions
### connect
**connect**(`uri`): `Promise`<[`Connection`](classes/Connection.md)\>
**connect**(`uri`): `Promise`<[`Connection`](interfaces/Connection.md)\>
Connect to a LanceDB instance at the given URI
@@ -54,8 +56,8 @@ Connect to a LanceDB instance at the given URI
#### Returns
`Promise`<[`Connection`](classes/Connection.md)\>
`Promise`<[`Connection`](interfaces/Connection.md)\>
#### Defined in
[index.ts:34](https://github.com/lancedb/lancedb/blob/31dab97/node/src/index.ts#L34)
[index.ts:34](https://github.com/lancedb/lancedb/blob/7247834/node/src/index.ts#L34)

View File

@@ -18,6 +18,7 @@ Currently, we support the following metrics:
| ----------- | ------------------------------------ |
| `L2` | [Euclidean / L2 distance](https://en.wikipedia.org/wiki/Euclidean_distance) |
| `Cosine` | [Cosine Similarity](https://en.wikipedia.org/wiki/Cosine_similarity)|
| `Dot` | [Dot Production](https://en.wikipedia.org/wiki/Dot_product) |
## Search
@@ -28,16 +29,44 @@ Currently, we support the following metrics:
If there is no [vector index is created](ann_indexes.md), LanceDB will just brute-force scan
the vector column and compute the distance.
<!-- Setup Code
```python
import lancedb
import numpy as np
uri = "data/sample-lancedb"
db = lancedb.connect(uri)
data = [{"vector": row, "item": f"item {i}"}
for i, row in enumerate(np.random.random((10_000, 1536)).astype('float32'))]
db.create_table("my_vectors", data=data)
```
-->
<!-- Setup Code
```javascript
const vectordb_setup = require('vectordb')
const db_setup = await vectordb_setup.connect('data/sample-lancedb')
let data = []
for (let i = 0; i < 10_000; i++) {
data.push({vector: Array(1536).fill(i), id: `${i}`, content: "", longId: `${i}`},)
}
await db_setup.createTable('my_vectors', data)
```
-->
=== "Python"
```python
import lancedb
import numpy as np
db = lancedb.connect("data/sample-lancedb")
tbl = db.open_table("my_vectors")
df = tbl.search(np.random.random((768)))
.limit(10)
df = tbl.search(np.random.random((1536))) \
.limit(10) \
.to_df()
```
@@ -47,38 +76,41 @@ the vector column and compute the distance.
const vectordb = require('vectordb')
const db = await vectordb.connect('data/sample-lancedb')
tbl = db.open_table("my_vectors")
const tbl = await db.openTable("my_vectors")
const results = await tbl.search(Array(768))
const results_1 = await tbl.search(Array(1536).fill(1.2))
.limit(20)
.execute()
```
<!-- Commenting out for now since metricType fails for JS on Ubuntu 22.04.
By default, `l2` will be used as `Metric` type. You can customize the metric type
as well.
-->
<!--
=== "Python"
```python
df = tbl.search(np.random.random((768)))
.metric("cosine")
.limit(10)
-->
<!-- ```python
df = tbl.search(np.random.random((1536))) \
.metric("cosine") \
.limit(10) \
.to_df()
```
-->
<!--
=== "JavaScript"
-->
```javascript
const vectordb = require('vectordb')
const db = await vectordb.connect('data/sample-lancedb')
tbl = db.open_table("my_vectors")
const results = await tbl.search(Array(768))
.metric("cosine")
<!-- ```javascript
const results_2 = await tbl.search(Array(1536).fill(1.2))
.metricType("cosine")
.limit(20)
.execute()
```
-->
### Search with Vector Index.

120
docs/src/sql.md Normal file
View File

@@ -0,0 +1,120 @@
# SQL filters
LanceDB embraces the utilization of standard SQL expressions as predicates for hybrid
filters. It can be used during hybrid vector search and deletion operations.
Currently, Lance supports a growing list of expressions.
* ``>``, ``>=``, ``<``, ``<=``, ``=``
* ``AND``, ``OR``, ``NOT``
* ``IS NULL``, ``IS NOT NULL``
* ``IS TRUE``, ``IS NOT TRUE``, ``IS FALSE``, ``IS NOT FALSE``
* ``IN``
* ``LIKE``, ``NOT LIKE``
* ``CAST``
* ``regexp_match(column, pattern)``
For example, the following filter string is acceptable:
<!-- Setup Code
```python
import lancedb
import numpy as np
uri = "data/sample-lancedb"
db = lancedb.connect(uri)
data = [{"vector": row, "item": f"item {i}"}
for i, row in enumerate(np.random.random((10_000, 2)).astype('int'))]
tbl = db.create_table("my_vectors", data=data)
```
-->
<!-- Setup Code
```javascript
const vectordb = require('vectordb')
const db = await vectordb.connect('data/sample-lancedb')
let data = []
for (let i = 0; i < 10_000; i++) {
data.push({vector: Array(1536).fill(i), id: `${i}`, content: "", longId: `${i}`},)
}
const tbl = await db.createTable('my_vectors', data)
```
-->
=== "Python"
```python
tbl.search([100, 102]) \
.where("""(
(label IN [10, 20])
AND
(note.email IS NOT NULL)
) OR NOT note.created
""")
```
=== "Javascript"
```javascript
tbl.search([100, 102])
.where(`(
(label IN [10, 20])
AND
(note.email IS NOT NULL)
) OR NOT note.created
`)
```
If your column name contains special characters or is a [SQL Keyword](https://docs.rs/sqlparser/latest/sqlparser/keywords/index.html),
you can use backtick (`` ` ``) to escape it. For nested fields, each segment of the
path must be wrapped in backticks.
=== "SQL"
```sql
`CUBE` = 10 AND `column name with space` IS NOT NULL
AND `nested with space`.`inner with space` < 2
```
!!! warning
Field names containing periods (``.``) are not supported.
Literals for dates, timestamps, and decimals can be written by writing the string
value after the type name. For example
=== "SQL"
```sql
date_col = date '2021-01-01'
and timestamp_col = timestamp '2021-01-01 00:00:00'
and decimal_col = decimal(8,3) '1.000'
```
For timestamp columns, the precision can be specified as a number in the type
parameter. Microsecond precision (6) is the default.
| SQL | Time unit |
|------------------|--------------|
| ``timestamp(0)`` | Seconds |
| ``timestamp(3)`` | Milliseconds |
| ``timestamp(6)`` | Microseconds |
| ``timestamp(9)`` | Nanoseconds |
LanceDB internally stores data in [Apache Arrow](https://arrow.apache.org/) format.
The mapping from SQL types to Arrow types is:
| SQL type | Arrow type |
|----------|------------|
| ``boolean`` | ``Boolean`` |
| ``tinyint`` / ``tinyint unsigned`` | ``Int8`` / ``UInt8`` |
| ``smallint`` / ``smallint unsigned`` | ``Int16`` / ``UInt16`` |
| ``int`` or ``integer`` / ``int unsigned`` or ``integer unsigned`` | ``Int32`` / ``UInt32`` |
| ``bigint`` / ``bigint unsigned`` | ``Int64`` / ``UInt64`` |
| ``float`` | ``Float32`` |
| ``double`` | ``Float64`` |
| ``decimal(precision, scale)`` | ``Decimal128`` |
| ``date`` | ``Date32`` |
| ``timestamp`` | ``Timestamp`` [^1] |
| ``string`` | ``Utf8`` |
| ``binary`` | ``Binary`` |
[^1]: See precision mapping in previous table.

51
docs/test/md_testing.js Normal file
View File

@@ -0,0 +1,51 @@
const glob = require("glob");
const fs = require("fs");
const path = require("path");
const excludedFiles = [
"../src/fts.md",
"../src/embedding.md",
"../src/examples/serverless_lancedb_with_s3_and_lambda.md",
"../src/examples/serverless_qa_bot_with_modal_and_langchain.md",
"../src/examples/youtube_transcript_bot_with_nodejs.md",
];
const nodePrefix = "javascript";
const nodeFile = ".js";
const nodeFolder = "node";
const globString = "../src/**/*.md";
const asyncPrefix = "(async () => {\n";
const asyncSuffix = "})();";
function* yieldLines(lines, prefix, suffix) {
let inCodeBlock = false;
for (const line of lines) {
if (line.trim().startsWith(prefix + nodePrefix)) {
inCodeBlock = true;
} else if (inCodeBlock && line.trim().startsWith(suffix)) {
inCodeBlock = false;
yield "\n";
} else if (inCodeBlock) {
yield line;
}
}
}
const files = glob.sync(globString, { recursive: true });
for (const file of files.filter((file) => !excludedFiles.includes(file))) {
const lines = [];
const data = fs.readFileSync(file, "utf-8");
const fileLines = data.split("\n");
for (const line of yieldLines(fileLines, "```", "```")) {
lines.push(line);
}
if (lines.length > 0) {
const fileName = path.basename(file, ".md");
const outPath = path.join(nodeFolder, fileName, `${fileName}${nodeFile}`);
console.log(outPath)
fs.mkdirSync(path.dirname(outPath), { recursive: true });
fs.writeFileSync(outPath, asyncPrefix + "\n" + lines.join("\n") + asyncSuffix);
}
}

41
docs/test/md_testing.py Normal file
View File

@@ -0,0 +1,41 @@
import glob
from typing import Iterator
from pathlib import Path
excluded_files = [
"../src/fts.md",
"../src/embedding.md",
"../src/examples/serverless_lancedb_with_s3_and_lambda.md",
"../src/examples/serverless_qa_bot_with_modal_and_langchain.md",
"../src/examples/youtube_transcript_bot_with_nodejs.md"
]
python_prefix = "py"
python_file = ".py"
python_folder = "python"
glob_string = "../src/**/*.md"
def yield_lines(lines: Iterator[str], prefix: str, suffix: str):
in_code_block = False
# Python code has strict indentation
strip_length = 0
for line in lines:
if line.strip().startswith(prefix + python_prefix):
in_code_block = True
strip_length = len(line) - len(line.lstrip())
elif in_code_block and line.strip().startswith(suffix):
in_code_block = False
yield "\n"
elif in_code_block:
yield line[strip_length:]
for file in filter(lambda file: file not in excluded_files, glob.glob(glob_string, recursive=True)):
with open(file, "r") as f:
lines = list(yield_lines(iter(f), "```", "```"))
if len(lines) > 0:
out_path = Path(python_folder) / Path(file).name.strip(".md") / (Path(file).name.strip(".md") + python_file)
print(out_path)
out_path.parent.mkdir(exist_ok=True, parents=True)
with open(out_path, "w") as out:
out.writelines(lines)

13
docs/test/package.json Normal file
View File

@@ -0,0 +1,13 @@
{
"name": "lancedb-docs-test",
"version": "1.0.0",
"description": "",
"author": "",
"license": "ISC",
"dependencies": {
"fs": "^0.0.1-security",
"glob": "^10.2.7",
"path": "^0.12.7",
"vectordb": "https://gitpkg.now.sh/lancedb/lancedb/node?main"
}
}

View File

@@ -0,0 +1,5 @@
lancedb @ git+https://github.com/lancedb/lancedb.git#egg=subdir&subdirectory=python
numpy
pandas
pylance
duckdb

View File

@@ -12,5 +12,6 @@ module.exports = {
sourceType: 'module'
},
rules: {
"@typescript-eslint/method-signature-style": "off",
}
}

View File

@@ -14,9 +14,11 @@ npm install vectordb
```javascript
const lancedb = require('vectordb');
const db = lancedb.connect('<PATH_TO_LANCEDB_DATASET>');
const table = await db.openTable('my_table');
const query = await table.search([0.1, 0.3]).setLimit(20).execute();
const db = await lancedb.connect('data/sample-lancedb');
const table = await db.createTable("my_table",
[{ id: 1, vector: [0.1, 1.0], item: "foo", price: 10.0 },
{ id: 2, vector: [3.9, 0.5], item: "bar", price: 20.0 }])
const results = await table.search([0.1, 0.3]).limit(20).execute();
console.log(results);
```
@@ -24,12 +26,6 @@ The [examples](./examples) folder contains complete examples.
## Development
The LanceDB javascript is built with npm:
```bash
npm run tsc
```
Run the tests with
```bash
@@ -46,4 +42,4 @@ To build documentation
```bash
npx typedoc --plugin typedoc-plugin-markdown --out ../docs/src/javascript src/index.ts
```
```

45
node/package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "vectordb",
"version": "0.1.8",
"version": "0.1.9",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "vectordb",
"version": "0.1.8",
"version": "0.1.9",
"license": "Apache-2.0",
"dependencies": {
"@apache-arrow/ts": "^12.0.0",
@@ -14,6 +14,7 @@
},
"devDependencies": {
"@types/chai": "^4.3.4",
"@types/chai-as-promised": "^7.1.5",
"@types/mocha": "^10.0.1",
"@types/node": "^18.16.2",
"@types/sinon": "^10.0.15",
@@ -21,6 +22,7 @@
"@typescript-eslint/eslint-plugin": "^5.59.1",
"cargo-cp-artifact": "^0.1",
"chai": "^4.3.7",
"chai-as-promised": "^7.1.1",
"eslint": "^8.39.0",
"eslint-config-standard-with-typescript": "^34.0.1",
"eslint-plugin-import": "^2.26.0",
@@ -311,6 +313,15 @@
"integrity": "sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==",
"dev": true
},
"node_modules/@types/chai-as-promised": {
"version": "7.1.5",
"resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-7.1.5.tgz",
"integrity": "sha512-jStwss93SITGBwt/niYrkf2C+/1KTeZCZl1LaeezTlqppAKeoQC7jxyqYuP72sxBGKCIbw7oHgbYssIRzT5FCQ==",
"dev": true,
"dependencies": {
"@types/chai": "*"
}
},
"node_modules/@types/command-line-args": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/@types/command-line-args/-/command-line-args-5.2.0.tgz",
@@ -942,6 +953,18 @@
"node": ">=4"
}
},
"node_modules/chai-as-promised": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz",
"integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==",
"dev": true,
"dependencies": {
"check-error": "^1.0.2"
},
"peerDependencies": {
"chai": ">= 2.1.2 < 5"
}
},
"node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@@ -4680,6 +4703,15 @@
"integrity": "sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==",
"dev": true
},
"@types/chai-as-promised": {
"version": "7.1.5",
"resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-7.1.5.tgz",
"integrity": "sha512-jStwss93SITGBwt/niYrkf2C+/1KTeZCZl1LaeezTlqppAKeoQC7jxyqYuP72sxBGKCIbw7oHgbYssIRzT5FCQ==",
"dev": true,
"requires": {
"@types/chai": "*"
}
},
"@types/command-line-args": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/@types/command-line-args/-/command-line-args-5.2.0.tgz",
@@ -5137,6 +5169,15 @@
"type-detect": "^4.0.5"
}
},
"chai-as-promised": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz",
"integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==",
"dev": true,
"requires": {
"check-error": "^1.0.2"
}
},
"chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",

View File

@@ -1,6 +1,6 @@
{
"name": "vectordb",
"version": "0.1.9",
"version": "0.1.10",
"description": " Serverless, low-latency vector database for AI applications",
"main": "dist/index.js",
"types": "dist/index.d.ts",
@@ -8,7 +8,7 @@
"tsc": "tsc -b",
"build": "cargo-cp-artifact --artifact cdylib vectordb-node index.node -- cargo build --message-format=json-render-diagnostics",
"build-release": "npm run build -- --release",
"test": "mocha -recursive dist/test",
"test": "npm run tsc; mocha -recursive dist/test",
"lint": "eslint src --ext .js,.ts",
"clean": "rm -rf node_modules *.node dist/"
},
@@ -26,6 +26,7 @@
"license": "Apache-2.0",
"devDependencies": {
"@types/chai": "^4.3.4",
"@types/chai-as-promised": "^7.1.5",
"@types/mocha": "^10.0.1",
"@types/node": "^18.16.2",
"@types/sinon": "^10.0.15",
@@ -33,6 +34,7 @@
"@typescript-eslint/eslint-plugin": "^5.59.1",
"cargo-cp-artifact": "^0.1",
"chai": "^4.3.7",
"chai-as-promised": "^7.1.1",
"eslint": "^8.39.0",
"eslint-config-standard-with-typescript": "^34.0.1",
"eslint-plugin-import": "^2.26.0",

View File

@@ -33,13 +33,99 @@ export { OpenAIEmbeddingFunction } from './embedding/openai'
*/
export async function connect (uri: string): Promise<Connection> {
const db = await databaseNew(uri)
return new Connection(db, uri)
return new LocalConnection(db, uri)
}
/**
* A LanceDB Connection that allows you to open tables and create new ones.
*
* Connection could be local against filesystem or remote against a server.
*/
export interface Connection {
uri: string
tableNames(): Promise<string[]>
/**
* Open a table in the database.
*
* @param name The name of the table.
* @param embeddings An embedding function to use on this table
*/
openTable<T>(name: string, embeddings?: EmbeddingFunction<T>): Promise<Table<T>>
/**
* Creates a new Table and initialize it with new data.
*
* @param {string} name - The name of the table.
* @param data - Non-empty Array of Records to be inserted into the table
* @param {WriteMode} mode - The write mode to use when creating the table.
* @param {EmbeddingFunction} embeddings - An embedding function to use on this table
*/
createTable<T>(name: string, data: Array<Record<string, unknown>>, mode?: WriteMode, embeddings?: EmbeddingFunction<T>): Promise<Table<T>>
createTableArrow(name: string, table: ArrowTable): Promise<Table>
/**
* Drop an existing table.
* @param name The name of the table to drop.
*/
dropTable(name: string): Promise<void>
}
/**
* A LanceDB Table is the collection of Records. Each Record has one or more vector fields.
*/
export interface Table<T = number[]> {
name: string
/**
* Creates a search query to find the nearest neighbors of the given search term
* @param query The query search term
*/
search: (query: T) => Query<T>
/**
* Insert records into this Table.
*
* @param data Records to be inserted into the Table
* @return The number of rows added to the table
*/
add: (data: Array<Record<string, unknown>>) => Promise<number>
/**
* Insert records into this Table, replacing its contents.
*
* @param data Records to be inserted into the Table
* @return The number of rows added to the table
*/
overwrite: (data: Array<Record<string, unknown>>) => Promise<number>
/**
* Create an ANN index on this Table vector index.
*
* @param indexParams The parameters of this Index, @see VectorIndexParams.
*/
createIndex: (indexParams: VectorIndexParams) => Promise<any>
/**
* Returns the number of rows in this table.
*/
countRows: () => Promise<number>
/**
* Delete rows from this table.
*
* @param filter A filter in the same format used by a sql WHERE clause.
*/
delete: (filter: string) => Promise<void>
}
/**
* A connection to a LanceDB database.
*/
export class Connection {
export class LocalConnection implements Connection {
private readonly _uri: string
private readonly _db: any
@@ -75,9 +161,9 @@ export class Connection {
async openTable<T> (name: string, embeddings?: EmbeddingFunction<T>): Promise<Table<T>> {
const tbl = await databaseOpenTable.call(this._db, name)
if (embeddings !== undefined) {
return new Table(tbl, name, embeddings)
return new LocalTable(tbl, name, embeddings)
} else {
return new Table(tbl, name)
return new LocalTable(tbl, name)
}
}
@@ -86,23 +172,29 @@ export class Connection {
*
* @param name The name of the table.
* @param data Non-empty Array of Records to be inserted into the Table
* @param mode The write mode to use when creating the table.
*/
async createTable (name: string, data: Array<Record<string, unknown>>, mode?: WriteMode): Promise<Table>
async createTable (name: string, data: Array<Record<string, unknown>>, mode: WriteMode): Promise<Table>
async createTable (name: string, data: Array<Record<string, unknown>>): Promise<Table>
/**
* Creates a new Table and initialize it with new data.
*
* @param name The name of the table.
* @param data Non-empty Array of Records to be inserted into the Table
* @param mode The write mode to use when creating the table.
* @param embeddings An embedding function to use on this Table
*/
async createTable<T> (name: string, data: Array<Record<string, unknown>>, embeddings: EmbeddingFunction<T>): Promise<Table<T>>
async createTable<T> (name: string, data: Array<Record<string, unknown>>, embeddings?: EmbeddingFunction<T>): Promise<Table<T>> {
const tbl = await tableCreate.call(this._db, name, await fromRecordsToBuffer(data, embeddings))
async createTable<T> (name: string, data: Array<Record<string, unknown>>, mode: WriteMode, embeddings: EmbeddingFunction<T>): Promise<Table<T>>
async createTable<T> (name: string, data: Array<Record<string, unknown>>, mode: WriteMode, embeddings?: EmbeddingFunction<T>): Promise<Table<T>> {
if (mode === undefined) {
mode = WriteMode.Create
}
const tbl = await tableCreate.call(this._db, name, await fromRecordsToBuffer(data, embeddings), mode.toLowerCase())
if (embeddings !== undefined) {
return new Table(tbl, name, embeddings)
return new LocalTable(tbl, name, embeddings)
} else {
return new Table(tbl, name)
return new LocalTable(tbl, name)
}
}
@@ -121,7 +213,7 @@ export class Connection {
}
}
export class Table<T = number[]> {
export class LocalTable<T = number[]> implements Table<T> {
private readonly _tbl: any
private readonly _name: string
private readonly _embeddings?: EmbeddingFunction<T>
@@ -180,13 +272,6 @@ export class Table<T = number[]> {
return tableCreateVectorIndex.call(this._tbl, indexParams)
}
/**
* @deprecated Use [Table.createIndex]
*/
async create_index (indexParams: VectorIndexParams): Promise<any> {
return await this.createIndex(indexParams)
}
/**
* Returns the number of rows in this table.
*/
@@ -197,14 +282,16 @@ export class Table<T = number[]> {
/**
* Delete rows from this table.
*
* @param filter The filter to be applied to this table.
* @param filter A filter in the same format used by a sql WHERE clause.
*/
async delete (filter: string): Promise<void> {
return tableDelete.call(this._tbl, filter)
}
}
interface IvfPQIndexConfig {
/// Config to build IVF_PQ index.
///
export interface IvfPQIndexConfig {
/**
* The column to be indexed
*/
@@ -249,6 +336,11 @@ interface IvfPQIndexConfig {
*/
max_opq_iters?: number
/**
* Replace an existing index with the same name if it exists.
*/
replace?: boolean
type: 'ivf_pq'
}
@@ -349,6 +441,7 @@ export class Query<T = number[]> {
const buffer = await tableSearch.call(this._tbl, this)
const data = tableFromIPC(buffer)
return data.toArray().map((entry: Record<string, unknown>) => {
const newObject: Record<string, unknown> = {}
Object.keys(entry).forEach((key: string) => {
@@ -363,8 +456,15 @@ export class Query<T = number[]> {
}
}
/**
* Write mode for writing a table.
*/
export enum WriteMode {
/** Create a new {@link Table}. */
Create = 'create',
/** Overwrite the existing {@link Table} if presented. */
Overwrite = 'overwrite',
/** Append new data to the table. */
Append = 'append'
}
@@ -380,5 +480,10 @@ export enum MetricType {
/**
* Cosine distance
*/
Cosine = 'cosine'
Cosine = 'cosine',
/**
* Dot product
*/
Dot = 'dot'
}

View File

@@ -1,4 +1,4 @@
// Copyright 2023 Lance Developers.
// Copyright 2023 LanceDB Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -13,11 +13,16 @@
// limitations under the License.
import { describe } from 'mocha'
import { assert } from 'chai'
import { track } from 'temp'
import * as chai from 'chai'
import * as chaiAsPromised from 'chai-as-promised'
import * as lancedb from '../index'
import { type EmbeddingFunction, MetricType, Query } from '../index'
import { type EmbeddingFunction, MetricType, Query, WriteMode } from '../index'
const expect = chai.expect
const assert = chai.assert
chai.use(chaiAsPromised)
describe('LanceDB client', function () {
describe('when creating a connection to lancedb', function () {
@@ -113,6 +118,31 @@ describe('LanceDB client', function () {
assert.equal(await table.countRows(), 2)
})
it('use overwrite flag to overwrite existing table', async function () {
const dir = await track().mkdir('lancejs')
const con = await lancedb.connect(dir)
const data = [
{ id: 1, vector: [0.1, 0.2], price: 10 },
{ id: 2, vector: [1.1, 1.2], price: 50 }
]
const tableName = 'overwrite'
await con.createTable(tableName, data, WriteMode.Create)
const newData = [
{ id: 1, vector: [0.1, 0.2], price: 10 },
{ id: 2, vector: [1.1, 1.2], price: 50 },
{ id: 3, vector: [1.1, 1.2], price: 50 }
]
await expect(con.createTable(tableName, newData)).to.be.rejectedWith(Error, 'already exists')
const table = await con.createTable(tableName, newData, WriteMode.Overwrite)
assert.equal(table.name, tableName)
assert.equal(await table.countRows(), 3)
})
it('appends records to an existing table ', async function () {
const dir = await track().mkdir('lancejs')
const con = await lancedb.connect(dir)
@@ -165,8 +195,25 @@ describe('LanceDB client', function () {
const uri = await createTestDB(32, 300)
const con = await lancedb.connect(uri)
const table = await con.openTable('vectors')
await table.createIndex({ type: 'ivf_pq', column: 'vector', num_partitions: 2, max_iters: 2 })
await table.createIndex({ type: 'ivf_pq', column: 'vector', num_partitions: 2, max_iters: 2, num_sub_vectors: 2 })
}).timeout(10_000) // Timeout is high partially because GH macos runner is pretty slow
it('replace an existing index', async function () {
const uri = await createTestDB(16, 300)
const con = await lancedb.connect(uri)
const table = await con.openTable('vectors')
await table.createIndex({ type: 'ivf_pq', column: 'vector', num_partitions: 2, max_iters: 2, num_sub_vectors: 2 })
// Replace should fail if the index already exists
await expect(table.createIndex({
type: 'ivf_pq', column: 'vector', num_partitions: 2, max_iters: 2, num_sub_vectors: 2, replace: false
})
).to.be.rejectedWith('LanceError(Index)')
// Default replace = true
await table.createIndex({ type: 'ivf_pq', column: 'vector', num_partitions: 2, max_iters: 2, num_sub_vectors: 2 })
}).timeout(50_000)
})
describe('when using a custom embedding function', function () {
@@ -196,7 +243,7 @@ describe('LanceDB client', function () {
{ price: 10, name: 'foo' },
{ price: 50, name: 'bar' }
]
const table = await con.createTable('vectors', data, embeddings)
const table = await con.createTable('vectors', data, WriteMode.Create, embeddings)
const results = await table.search('foo').execute()
assert.equal(results.length, 2)
})

85
python/README.md Normal file
View File

@@ -0,0 +1,85 @@
# LanceDB
A Python library for [LanceDB](https://github.com/lancedb/lancedb).
## Installation
```bash
pip install lancedb
```
## Usage
### Basic Example
```python
import lancedb
db = lancedb.connect('<PATH_TO_LANCEDB_DATASET>')
table = db.open_table('my_table')
results = table.search([0.1, 0.3]).limit(20).to_df()
print(results)
```
## Development
Create a virtual environment and activate it:
```bash
python -m venv venv
. ./venv/bin/activate
```
Install the necessary packages:
```bash
python -m pip install .
```
To run the unit tests:
```bash
pytest
```
To run linter and automatically fix all errors:
```bash
black .
isort .
```
If any packages are missing, install them with:
```bash
pip install <PACKAGE_NAME>
```
___
For **Windows** users, there may be errors when installing packages, so these commands may be helpful:
Activate the virtual environment:
```bash
. .\venv\Scripts\activate
```
You may need to run the installs separately:
```bash
pip install -e .[tests]
pip install -e .[dev]
```
`tantivy` requires `rust` to be installed, so install it with `conda`, as it doesn't support windows installation:
```bash
pip install wheel
pip install cargo
conda install rust
pip install tantivy
```
To run the unit tests:
```bash
pytest
```

View File

@@ -158,6 +158,8 @@ class LanceDBConnection:
data: DATA = None,
schema: pa.Schema = None,
mode: str = "create",
on_bad_vectors: str = "drop",
fill_value: float = 0.0,
) -> LanceTable:
"""Create a table in the database.
@@ -170,9 +172,14 @@ class LanceDBConnection:
schema: pyarrow.Schema; optional
The schema of the table.
mode: str; default "create"
The mode to use when creating the table.
The mode to use when creating the table. Can be either "create" or "overwrite".
By default, if the table already exists, an exception is raised.
If you want to overwrite the table, use mode="overwrite".
on_bad_vectors: str
What to do if any of the vectors are not the same size or contains NaNs.
One of "raise", "drop", "fill".
fill_value: float
The value to use when filling vectors. Only used if on_bad_vectors="fill".
Note
----
@@ -249,10 +256,21 @@ class LanceDBConnection:
lat: [[45.5,40.1]]
long: [[-122.7,-74.1]]
"""
if mode.lower() not in ["create", "overwrite"]:
raise ValueError("mode must be either 'create' or 'overwrite'")
if data is not None:
tbl = LanceTable.create(self, name, data, schema, mode=mode)
tbl = LanceTable.create(
self,
name,
data,
schema,
mode=mode,
on_bad_vectors=on_bad_vectors,
fill_value=fill_value,
)
else:
tbl = LanceTable(self, name)
tbl = LanceTable.open(self, name)
return tbl
def open_table(self, name: str) -> LanceTable:
@@ -267,7 +285,7 @@ class LanceDBConnection:
-------
A LanceTable object representing the table.
"""
return LanceTable(self, name)
return LanceTable.open(self, name)
def drop_table(self, name: str):
"""Drop a table from the database.

View File

@@ -45,7 +45,12 @@ class LanceQueryBuilder:
0 6 [0.4, 0.4] 0.0
"""
def __init__(self, table: "lancedb.table.LanceTable", query: np.ndarray):
def __init__(
self,
table: "lancedb.table.LanceTable",
query: np.ndarray,
vector_column_name: str = VECTOR_COLUMN_NAME,
):
self._metric = "L2"
self._nprobes = 20
self._refine_factor = None
@@ -54,6 +59,7 @@ class LanceQueryBuilder:
self._limit = 10
self._columns = None
self._where = None
self._vector_column_name = vector_column_name
def limit(self, limit: int) -> LanceQueryBuilder:
"""Set the maximum number of results to return.
@@ -195,7 +201,7 @@ class LanceQueryBuilder:
columns=self._columns,
filter=self._where,
nearest={
"column": VECTOR_COLUMN_NAME,
"column": self._vector_column_name,
"q": self._query,
"k": self._limit,
"metric": self._metric,

View File

@@ -15,12 +15,13 @@ from __future__ import annotations
import os
from functools import cached_property
from typing import List, Union
from typing import Any, List, Union
import lance
import numpy as np
import pandas as pd
import pyarrow as pa
import pyarrow.compute as pc
from lance import LanceDataset
from lance.vector import vec_to_table
@@ -28,15 +29,19 @@ from .common import DATA, VEC, VECTOR_COLUMN_NAME
from .query import LanceFtsQueryBuilder, LanceQueryBuilder
def _sanitize_data(data, schema):
def _sanitize_data(data, schema, on_bad_vectors, fill_value):
if isinstance(data, list):
data = pa.Table.from_pylist(data)
data = _sanitize_schema(data, schema=schema)
data = _sanitize_schema(
data, schema=schema, on_bad_vectors=on_bad_vectors, fill_value=fill_value
)
if isinstance(data, dict):
data = vec_to_table(data)
if isinstance(data, pd.DataFrame):
data = pa.Table.from_pandas(data)
data = _sanitize_schema(data, schema=schema)
data = _sanitize_schema(
data, schema=schema, on_bad_vectors=on_bad_vectors, fill_value=fill_value
)
if not isinstance(data, pa.Table):
raise TypeError(f"Unsupported data type: {type(data)}")
return data
@@ -182,13 +187,21 @@ class LanceTable:
def _dataset_uri(self) -> str:
return os.path.join(self._conn.uri, f"{self.name}.lance")
def create_index(self, metric="L2", num_partitions=256, num_sub_vectors=96):
def create_index(
self,
metric="L2",
num_partitions=256,
num_sub_vectors=96,
vector_column_name=VECTOR_COLUMN_NAME,
replace: bool = True,
):
"""Create an index on the table.
Parameters
----------
metric: str, default "L2"
The distance metric to use when creating the index. Valid values are "L2" or "cosine".
The distance metric to use when creating the index.
Valid values are "L2", "cosine", or "dot".
L2 is euclidean distance.
num_partitions: int
The number of IVF partitions to use when creating the index.
@@ -196,13 +209,19 @@ class LanceTable:
num_sub_vectors: int
The number of PQ sub-vectors to use when creating the index.
Default is 96.
vector_column_name: str, default "vector"
The vector column name to create the index.
replace: bool, default True
If True, replace the existing index if it exists.
If False, raise an error if duplicate index exists.
"""
self._dataset.create_index(
column=VECTOR_COLUMN_NAME,
column=vector_column_name,
index_type="IVF_PQ",
metric=metric,
num_partitions=num_partitions,
num_sub_vectors=num_sub_vectors,
replace=replace,
)
self._reset_dataset()
@@ -235,7 +254,13 @@ class LanceTable:
"""Return the LanceDataset backing this table."""
return self._dataset
def add(self, data: DATA, mode: str = "append") -> int:
def add(
self,
data: DATA,
mode: str = "append",
on_bad_vectors: str = "drop",
fill_value: float = 0.0,
) -> int:
"""Add data to the table.
Parameters
@@ -245,18 +270,27 @@ class LanceTable:
mode: str
The mode to use when writing the data. Valid values are
"append" and "overwrite".
on_bad_vectors: str
What to do if any of the vectors are not the same size or contains NaNs.
One of "raise", "drop", "fill".
fill_value: float, default 0.
The value to use when filling vectors. Only used if on_bad_vectors="fill".
Returns
-------
int
The number of vectors in the table.
"""
data = _sanitize_data(data, self.schema)
data = _sanitize_data(
data, self.schema, on_bad_vectors=on_bad_vectors, fill_value=fill_value
)
lance.write_dataset(data, self._dataset_uri, mode=mode)
self._reset_dataset()
return len(self)
def search(self, query: Union[VEC, str]) -> LanceQueryBuilder:
def search(
self, query: Union[VEC, str], vector_column_name=VECTOR_COLUMN_NAME
) -> LanceQueryBuilder:
"""Create a search query to find the nearest neighbors
of the given query vector.
@@ -264,6 +298,8 @@ class LanceTable:
----------
query: list, np.ndarray
The query vector.
vector_column_name: str, default "vector"
The name of the vector column to search.
Returns
-------
@@ -275,7 +311,7 @@ class LanceTable:
"""
if isinstance(query, str):
# fts
return LanceFtsQueryBuilder(self, query)
return LanceFtsQueryBuilder(self, query, vector_column_name)
if isinstance(query, list):
query = np.array(query)
@@ -283,15 +319,74 @@ class LanceTable:
query = query.astype(np.float32)
else:
raise TypeError(f"Unsupported query type: {type(query)}")
return LanceQueryBuilder(self, query)
return LanceQueryBuilder(self, query, vector_column_name)
@classmethod
def create(cls, db, name, data, schema=None, mode="create"):
def create(
cls,
db,
name,
data,
schema=None,
mode="create",
on_bad_vectors: str = "drop",
fill_value: float = 0.0,
):
"""
Create a new table.
Examples
--------
>>> import lancedb
>>> import pandas as pd
>>> data = pd.DataFrame({"x": [1, 2, 3], "vector": [[1, 2], [3, 4], [5, 6]]})
>>> db = lancedb.connect("./.lancedb")
>>> table = db.create_table("my_table", data)
>>> table.to_pandas()
x vector
0 1 [1.0, 2.0]
1 2 [3.0, 4.0]
2 3 [5.0, 6.0]
Parameters
----------
db: LanceDB
The LanceDB instance to create the table in.
name: str
The name of the table to create.
data: list-of-dict, dict, pd.DataFrame
The data to insert into the table.
schema: dict, optional
The schema of the table. If not provided, the schema is inferred from the data.
mode: str, default "create"
The mode to use when writing the data. Valid values are
"create", "overwrite", and "append".
on_bad_vectors: str
What to do if any of the vectors are not the same size or contains NaNs.
One of "raise", "drop", "fill".
fill_value: float, default 0.
The value to use when filling vectors. Only used if on_bad_vectors="fill".
"""
tbl = LanceTable(db, name)
data = _sanitize_data(data, schema)
data = _sanitize_data(
data, schema, on_bad_vectors=on_bad_vectors, fill_value=fill_value
)
lance.write_dataset(data, tbl._dataset_uri, mode=mode)
return tbl
@classmethod
def open(cls, db, name):
tbl = cls(db, name)
if tbl._conn.is_managed_remote:
# Not completely sure how to check for remote table existence yet.
return tbl
if not os.path.exists(tbl._dataset_uri):
raise FileNotFoundError(
f"Table {name} does not exist. Please first call db.create_table({name}, data)"
)
return tbl
def delete(self, where: str):
"""Delete rows from the table.
@@ -321,7 +416,12 @@ class LanceTable:
self._dataset.delete(where)
def _sanitize_schema(data: pa.Table, schema: pa.Schema = None) -> pa.Table:
def _sanitize_schema(
data: pa.Table,
schema: pa.Schema = None,
on_bad_vectors: str = "drop",
fill_value: float = 0.0,
) -> pa.Table:
"""Ensure that the table has the expected schema.
Parameters
@@ -331,21 +431,41 @@ def _sanitize_schema(data: pa.Table, schema: pa.Schema = None) -> pa.Table:
schema: pa.Schema; optional
The expected schema. If not provided, this just converts the
vector column to fixed_size_list(float32) if necessary.
on_bad_vectors: str
What to do if any of the vectors are not the same size or contains NaNs.
One of "raise", "drop", "fill".
fill_value: float
The value to use when filling vectors. Only used if on_bad_vectors="fill".
"""
if schema is not None:
if data.schema == schema:
return data
# cast the columns to the expected types
data = data.combine_chunks()
data = _sanitize_vector_column(data, vector_column_name=VECTOR_COLUMN_NAME)
data = _sanitize_vector_column(
data,
vector_column_name=VECTOR_COLUMN_NAME,
on_bad_vectors=on_bad_vectors,
fill_value=fill_value,
)
return pa.Table.from_arrays(
[data[name] for name in schema.names], schema=schema
)
# just check the vector column
return _sanitize_vector_column(data, vector_column_name=VECTOR_COLUMN_NAME)
return _sanitize_vector_column(
data,
vector_column_name=VECTOR_COLUMN_NAME,
on_bad_vectors=on_bad_vectors,
fill_value=fill_value,
)
def _sanitize_vector_column(data: pa.Table, vector_column_name: str) -> pa.Table:
def _sanitize_vector_column(
data: pa.Table,
vector_column_name: str,
on_bad_vectors: str = "drop",
fill_value: float = 0.0,
) -> pa.Table:
"""
Ensure that the vector column exists and has type fixed_size_list(float32)
@@ -355,19 +475,103 @@ def _sanitize_vector_column(data: pa.Table, vector_column_name: str) -> pa.Table
The table to sanitize.
vector_column_name: str
The name of the vector column.
on_bad_vectors: str
What to do if any of the vectors are not the same size or contains NaNs.
One of "raise", "drop", "fill".
fill_value: float
The value to use when filling vectors. Only used if on_bad_vectors="fill".
"""
if vector_column_name not in data.column_names:
raise ValueError(f"Missing vector column: {vector_column_name}")
# ChunkedArray is annoying to work with, so we combine chunks here
vec_arr = data[vector_column_name].combine_chunks()
if pa.types.is_fixed_size_list(vec_arr.type):
return data
if not pa.types.is_list(vec_arr.type):
if pa.types.is_list(data[vector_column_name].type):
# if it's a variable size list array we make sure the dimensions are all the same
has_jagged_ndims = len(vec_arr.values) % len(data) != 0
if has_jagged_ndims:
data = _sanitize_jagged(
data, fill_value, on_bad_vectors, vec_arr, vector_column_name
)
vec_arr = data[vector_column_name].combine_chunks()
elif not pa.types.is_fixed_size_list(vec_arr.type):
raise TypeError(f"Unsupported vector column type: {vec_arr.type}")
vec_arr = ensure_fixed_size_list_of_f32(vec_arr)
data = data.set_column(
data.column_names.index(vector_column_name), vector_column_name, vec_arr
)
has_nans = pc.any(vec_arr.values.is_nan()).as_py()
if has_nans:
data = _sanitize_nans(
data, fill_value, on_bad_vectors, vec_arr, vector_column_name
)
return data
def ensure_fixed_size_list_of_f32(vec_arr):
values = vec_arr.values
if not pa.types.is_float32(values.type):
values = values.cast(pa.float32())
list_size = len(values) / len(data)
if pa.types.is_fixed_size_list(vec_arr.type):
list_size = vec_arr.type.list_size
else:
list_size = len(values) / len(vec_arr)
vec_arr = pa.FixedSizeListArray.from_arrays(values, list_size)
return data.set_column(
data.column_names.index(vector_column_name), vector_column_name, vec_arr
)
return vec_arr
def _sanitize_jagged(data, fill_value, on_bad_vectors, vec_arr, vector_column_name):
"""Sanitize jagged vectors."""
if on_bad_vectors == "raise":
raise ValueError(
f"Vector column {vector_column_name} has variable length vectors "
"Set on_bad_vectors='drop' to remove them, or "
"set on_bad_vectors='fill' and fill_value=<value> to replace them."
)
lst_lengths = pc.list_value_length(vec_arr)
ndims = pc.max(lst_lengths).as_py()
correct_ndims = pc.equal(lst_lengths, ndims)
if on_bad_vectors == "fill":
if fill_value is None:
raise ValueError(
f"`fill_value` must not be None if `on_bad_vectors` is 'fill'"
)
fill_arr = pa.scalar([float(fill_value)] * ndims)
vec_arr = pc.if_else(correct_ndims, vec_arr, fill_arr)
data = data.set_column(
data.column_names.index(vector_column_name), vector_column_name, vec_arr
)
elif on_bad_vectors == "drop":
data = data.filter(correct_ndims)
return data
def _sanitize_nans(data, fill_value, on_bad_vectors, vec_arr, vector_column_name):
"""Sanitize NaNs in vectors"""
if on_bad_vectors == "raise":
raise ValueError(
f"Vector column {vector_column_name} has NaNs. "
"Set on_bad_vectors='drop' to remove them, or "
"set on_bad_vectors='fill' and fill_value=<value> to replace them."
)
elif on_bad_vectors == "fill":
if fill_value is None:
raise ValueError(
f"`fill_value` must not be None if `on_bad_vectors` is 'fill'"
)
fill_value = float(fill_value)
values = pc.if_else(vec_arr.values.is_nan(), fill_value, vec_arr.values)
ndims = len(vec_arr[0])
vec_arr = pa.FixedSizeListArray.from_arrays(values, ndims)
data = data.set_column(
data.column_names.index(vector_column_name), vector_column_name, vec_arr
)
elif on_bad_vectors == "drop":
is_value_nan = pc.is_nan(vec_arr.values).to_numpy(zero_copy_only=False)
is_full = np.any(~is_value_nan.reshape(-1, vec_arr.type.list_size), axis=1)
data = data.filter(is_full)
return data

View File

@@ -11,6 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import numpy as np
import pandas as pd
import pytest
@@ -120,3 +121,40 @@ def test_delete_table(tmp_path):
db.create_table("test", data=data)
assert db.table_names() == ["test"]
def test_empty_or_nonexistent_table(tmp_path):
db = lancedb.connect(tmp_path)
with pytest.raises(Exception):
db.create_table("test_with_no_data")
with pytest.raises(Exception):
db.open_table("does_not_exist")
def test_replace_index(tmp_path):
db = lancedb.connect(uri=tmp_path)
table = db.create_table(
"test",
[
{"vector": np.random.rand(128), "item": "foo", "price": float(i)}
for i in range(1000)
],
)
table.create_index(
num_partitions=2,
num_sub_vectors=4,
)
with pytest.raises(Exception):
table.create_index(
num_partitions=2,
num_sub_vectors=4,
replace=False,
)
table.create_index(
num_partitions=2,
num_sub_vectors=4,
replace=True,
)

View File

@@ -11,15 +11,17 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest.mock as mock
import lance
import numpy as np
import pandas as pd
import pandas.testing as tm
import pyarrow as pa
import pytest
from lancedb.db import LanceDBConnection
from lancedb.query import LanceQueryBuilder
from lancedb.table import LanceTable
class MockTable:
@@ -48,24 +50,30 @@ def table(tmp_path) -> MockTable:
def test_query_builder(table):
df = LanceQueryBuilder(table, [0, 0]).limit(1).select(["id"]).to_df()
df = LanceQueryBuilder(table, [0, 0], "vector").limit(1).select(["id"]).to_df()
assert df["id"].values[0] == 1
assert all(df["vector"].values[0] == [1, 2])
def test_query_builder_with_filter(table):
df = LanceQueryBuilder(table, [0, 0]).where("id = 2").to_df()
df = LanceQueryBuilder(table, [0, 0], "vector").where("id = 2").to_df()
assert df["id"].values[0] == 2
assert all(df["vector"].values[0] == [3, 4])
def test_query_builder_with_metric(table):
query = [4, 8]
df_default = LanceQueryBuilder(table, query).to_df()
df_l2 = LanceQueryBuilder(table, query).metric("L2").to_df()
vector_column_name = "vector"
df_default = LanceQueryBuilder(table, query, vector_column_name).to_df()
df_l2 = LanceQueryBuilder(table, query, vector_column_name).metric("L2").to_df()
tm.assert_frame_equal(df_default, df_l2)
df_cosine = LanceQueryBuilder(table, query).metric("cosine").limit(1).to_df()
df_cosine = (
LanceQueryBuilder(table, query, vector_column_name)
.metric("cosine")
.limit(1)
.to_df()
)
assert df_cosine.score[0] == pytest.approx(
cosine_distance(query, df_cosine.vector[0]),
abs=1e-6,
@@ -73,5 +81,35 @@ def test_query_builder_with_metric(table):
assert 0 <= df_cosine.score[0] <= 1
def test_query_builder_with_different_vector_column():
table = mock.MagicMock(spec=LanceTable)
query = [4, 8]
vector_column_name = "foo_vector"
builder = (
LanceQueryBuilder(table, query, vector_column_name)
.metric("cosine")
.where("b < 10")
.select(["b"])
.limit(2)
)
ds = mock.Mock()
table.to_lance.return_value = ds
table._conn = mock.MagicMock()
table._conn.is_managed_remote = False
builder.to_arrow()
ds.to_table.assert_called_once_with(
columns=["b"],
filter="b < 10",
nearest={
"column": vector_column_name,
"q": query,
"k": 2,
"metric": "cosine",
"nprobes": 20,
"refine_factor": None,
},
)
def cosine_distance(vec1, vec2):
return 1 - np.dot(vec1, vec2) / (np.linalg.norm(vec1) * np.linalg.norm(vec2))

View File

@@ -30,7 +30,7 @@ class MockLanceDBServer:
table_name = request.match_info["table_name"]
assert table_name == "test_table"
request_json = await request.json()
await request.json()
# TODO: do some matching
vecs = pd.Series([np.random.rand(128) for x in range(10)], name="vector")

View File

@@ -13,11 +13,14 @@
import functools
from pathlib import Path
from unittest.mock import PropertyMock, patch
import numpy as np
import pandas as pd
import pyarrow as pa
import pytest
from lancedb.db import LanceDBConnection
from lancedb.table import LanceTable
@@ -142,3 +145,83 @@ def test_versioning(db):
table.checkout(1)
assert table.version == 1
assert len(table) == 2
def test_create_index_method():
with patch.object(LanceTable, "_reset_dataset", return_value=None):
with patch.object(
LanceTable, "_dataset", new_callable=PropertyMock
) as mock_dataset:
# Setup mock responses
mock_dataset.return_value.create_index.return_value = None
# Create a LanceTable object
connection = LanceDBConnection(uri="mock.uri")
table = LanceTable(connection, "test_table")
# Call the create_index method
table.create_index(
metric="L2",
num_partitions=256,
num_sub_vectors=96,
vector_column_name="vector",
replace=True,
)
# Check that the _dataset.create_index method was called
# with the right parameters
mock_dataset.return_value.create_index.assert_called_once_with(
column="vector",
index_type="IVF_PQ",
metric="L2",
num_partitions=256,
num_sub_vectors=96,
replace=True,
)
def test_add_with_nans(db):
# By default we drop bad input vectors
table = LanceTable.create(
db,
"drop_test",
data=[
{"vector": [3.1, 4.1], "item": "foo", "price": 10.0},
{"vector": [np.nan], "item": "bar", "price": 20.0},
{"vector": [5], "item": "bar", "price": 20.0},
{"vector": [np.nan, np.nan], "item": "bar", "price": 20.0},
],
)
assert len(table) == 1
# We can fill bad input with some value
table = LanceTable.create(
db,
"fill_test",
data=[
{"vector": [3.1, 4.1], "item": "foo", "price": 10.0},
{"vector": [np.nan], "item": "bar", "price": 20.0},
{"vector": [np.nan, np.nan], "item": "bar", "price": 20.0},
],
on_bad_vectors="fill",
fill_value=0.0,
)
assert len(table) == 3
arrow_tbl = table.to_lance().to_table(filter="item == 'bar'")
v = arrow_tbl["vector"].to_pylist()[0]
assert np.allclose(v, np.array([0.0, 0.0]))
bad_data = [
{"vector": [np.nan], "item": "bar", "price": 20.0},
{"vector": [5], "item": "bar", "price": 20.0},
{"vector": [np.nan, np.nan], "item": "bar", "price": 20.0},
{"vector": [np.nan, 5.0], "item": "bar", "price": 20.0},
]
for row in bad_data:
with pytest.raises(ValueError):
LanceTable.create(
db,
"raise_test",
data=[{"vector": [3.1, 4.1], "item": "foo", "price": 10.0}, row],
on_bad_vectors="raise",
)

View File

@@ -1,6 +1,6 @@
[package]
name = "vectordb-node"
version = "0.1.9"
version = "0.1.10"
description = "Serverless, low-latency vector database for AI applications"
license = "Apache-2.0"
edition = "2018"
@@ -10,12 +10,12 @@ exclude = ["index.node"]
crate-type = ["cdylib"]
[dependencies]
arrow-array = "40.0"
arrow-ipc = "40.0"
arrow-schema = "40.0"
arrow-array = { workspace = true }
arrow-ipc = { workspace = true }
arrow-schema = { workspace = true }
once_cell = "1"
futures = "0.3"
lance = "0.5.0"
lance = { workspace = true }
vectordb = { path = "../../vectordb" }
tokio = { version = "1.23", features = ["rt-multi-thread"] }
neon = {version = "0.10.1", default-features = false, features = ["channel-api", "napi-6", "promise-api", "task-api"] }

View File

@@ -122,6 +122,10 @@ fn get_index_params_builder(
.map_err(|t| t.to_string())?
.map(|s| pq_params.max_opq_iters = s.value(cx) as usize);
obj.get_opt::<JsBoolean, _, _>(cx, "replace")
.map_err(|t| t.to_string())?
.map(|s| index_builder.replace(s.value(cx)));
Ok(index_builder)
}
t => Err(format!("{} is not a valid index type", t).to_string()),

View File

@@ -17,11 +17,10 @@ use std::convert::TryFrom;
use std::ops::Deref;
use std::sync::{Arc, Mutex};
use arrow_array::{Float32Array, RecordBatchReader};
use arrow_array::{Float32Array, RecordBatchIterator, RecordBatchReader};
use arrow_ipc::writer::FileWriter;
use futures::{TryFutureExt, TryStreamExt};
use lance::arrow::RecordBatchBuffer;
use lance::dataset::WriteMode;
use lance::dataset::{WriteMode, WriteParams};
use lance::index::vector::MetricType;
use neon::prelude::*;
use neon::types::buffer::TypedArray;
@@ -233,6 +232,17 @@ fn table_create(mut cx: FunctionContext) -> JsResult<JsPromise> {
let table_name = cx.argument::<JsString>(0)?.value(&mut cx);
let buffer = cx.argument::<JsBuffer>(1)?;
let batches = arrow_buffer_to_record_batch(buffer.as_slice(&mut cx));
let schema = batches[0].schema();
// Write mode
let mode = match cx.argument::<JsString>(2)?.value(&mut cx).as_str() {
"overwrite" => WriteMode::Overwrite,
"append" => WriteMode::Append,
"create" => WriteMode::Create,
_ => return cx.throw_error("Table::create only supports 'overwrite' and 'create' modes"),
};
let mut params = WriteParams::default();
params.mode = mode;
let rt = runtime(&mut cx)?;
let channel = cx.channel();
@@ -241,8 +251,13 @@ fn table_create(mut cx: FunctionContext) -> JsResult<JsPromise> {
let database = db.database.clone();
rt.block_on(async move {
let batch_reader: Box<dyn RecordBatchReader> = Box::new(RecordBatchBuffer::new(batches));
let table_rst = database.create_table(&table_name, batch_reader).await;
let batch_reader: Box<dyn RecordBatchReader> = Box::new(RecordBatchIterator::new(
batches.into_iter().map(Ok),
schema,
));
let table_rst = database
.create_table(&table_name, batch_reader, Some(params))
.await;
deferred.settle_with(&channel, move |mut cx| {
let table = Arc::new(Mutex::new(
@@ -265,6 +280,7 @@ fn table_add(mut cx: FunctionContext) -> JsResult<JsPromise> {
let buffer = cx.argument::<JsBuffer>(0)?;
let write_mode = cx.argument::<JsString>(1)?.value(&mut cx);
let batches = arrow_buffer_to_record_batch(buffer.as_slice(&mut cx));
let schema = batches[0].schema();
let rt = runtime(&mut cx)?;
let channel = cx.channel();
@@ -274,7 +290,10 @@ fn table_add(mut cx: FunctionContext) -> JsResult<JsPromise> {
let write_mode = write_mode_map.get(write_mode.as_str()).cloned();
rt.block_on(async move {
let batch_reader: Box<dyn RecordBatchReader> = Box::new(RecordBatchBuffer::new(batches));
let batch_reader: Box<dyn RecordBatchReader> = Box::new(RecordBatchIterator::new(
batches.into_iter().map(Ok),
schema,
));
let add_result = table.lock().unwrap().add(batch_reader, write_mode).await;
deferred.settle_with(&channel, move |mut cx| {

View File

@@ -1,20 +1,19 @@
[package]
name = "vectordb"
version = "0.1.9"
version = "0.1.10"
edition = "2021"
description = "Serverless, low-latency vector database for AI applications"
license = "Apache-2.0"
repository = "https://github.com/lancedb/lancedb"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
arrow-array = "40.0"
arrow-data = "40.0"
arrow-schema = "40.0"
object_store = "0.6.1"
arrow-array = { workspace = true }
arrow-data = { workspace = true }
arrow-schema = { workspace = true }
object_store = { workspace = true }
snafu = "0.7.4"
lance = "0.5.0"
lance = { workspace = true }
tokio = { version = "1.23", features = ["rt-multi-thread"] }
[dev-dependencies]

View File

@@ -16,11 +16,12 @@ use std::fs::create_dir_all;
use std::path::Path;
use arrow_array::RecordBatchReader;
use lance::dataset::WriteParams;
use lance::io::object_store::ObjectStore;
use snafu::prelude::*;
use crate::error::{CreateDirSnafu, Result};
use crate::table::Table;
use crate::table::{OpenTableParams, Table};
pub struct Database {
object_store: ObjectStore,
@@ -90,12 +91,19 @@ impl Database {
Ok(f)
}
/// Create a new table in the database.
///
/// # Arguments
/// * `name` - The name of the table.
/// * `batches` - The initial data to write to the table.
/// * `params` - Optional [`WriteParams`] to create the table.
pub async fn create_table(
&self,
name: &str,
batches: Box<dyn RecordBatchReader>,
params: Option<WriteParams>,
) -> Result<Table> {
Table::create(&self.uri, name, batches).await
Table::create(&self.uri, name, batches, params).await
}
/// Open a table in the database.
@@ -107,7 +115,25 @@ impl Database {
///
/// * A [Table] object.
pub async fn open_table(&self, name: &str) -> Result<Table> {
Table::open(&self.uri, name).await
self.open_table_with_params(name, OpenTableParams::default())
.await
}
/// Open a table in the database.
///
/// # Arguments
/// * `name` - The name of the table.
/// * `params` - The parameters to open the table.
///
/// # Returns
///
/// * A [Table] object.
pub async fn open_table_with_params(
&self,
name: &str,
params: OpenTableParams,
) -> Result<Table> {
Table::open_with_params(&self.uri, name, params).await
}
/// Drop a table in the database.

View File

@@ -19,3 +19,6 @@ pub mod query;
pub mod table;
pub use database::Database;
pub use table::Table;
pub use lance::dataset::WriteMode;

View File

@@ -164,9 +164,8 @@ impl Query {
mod tests {
use std::sync::Arc;
use arrow_array::{Float32Array, RecordBatch, RecordBatchReader};
use arrow_array::{Float32Array, RecordBatch, RecordBatchIterator, RecordBatchReader};
use arrow_schema::{DataType, Field as ArrowField, Schema as ArrowSchema};
use lance::arrow::RecordBatchBuffer;
use lance::dataset::Dataset;
use lance::index::vector::MetricType;
@@ -174,7 +173,7 @@ mod tests {
#[tokio::test]
async fn test_setters_getters() {
let mut batches: Box<dyn RecordBatchReader> = Box::new(make_test_batches());
let mut batches: Box<dyn RecordBatchReader> = make_test_batches();
let ds = Dataset::write(&mut batches, "memory://foo", None)
.await
.unwrap();
@@ -203,7 +202,7 @@ mod tests {
#[tokio::test]
async fn test_execute() {
let mut batches: Box<dyn RecordBatchReader> = Box::new(make_test_batches());
let mut batches: Box<dyn RecordBatchReader> = make_test_batches();
let ds = Dataset::write(&mut batches, "memory://foo", None)
.await
.unwrap();
@@ -214,7 +213,7 @@ mod tests {
assert_eq!(result.is_ok(), true);
}
fn make_test_batches() -> RecordBatchBuffer {
fn make_test_batches() -> Box<dyn RecordBatchReader> {
let dim: usize = 128;
let schema = Arc::new(ArrowSchema::new(vec![
ArrowField::new("key", DataType::Int32, false),
@@ -228,7 +227,11 @@ mod tests {
),
ArrowField::new("uri", DataType::Utf8, true),
]));
RecordBatchBuffer::new(vec![RecordBatch::new_empty(schema.clone())])
Box::new(RecordBatchIterator::new(
vec![RecordBatch::new_empty(schema.clone())]
.into_iter()
.map(Ok),
schema,
))
}
}

View File

@@ -1,4 +1,4 @@
// Copyright 2023 Lance Developers.
// Copyright 2023 LanceDB Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -16,12 +16,13 @@ use std::path::Path;
use std::sync::Arc;
use arrow_array::{Float32Array, RecordBatchReader};
use lance::dataset::{Dataset, WriteMode, WriteParams};
use lance::dataset::{Dataset, ReadParams, WriteParams};
use lance::index::IndexType;
use snafu::prelude::*;
use crate::error::{Error, InvalidTableNameSnafu, Result};
use crate::index::vector::VectorIndexBuilder;
use crate::WriteMode;
use crate::query::Query;
pub const VECTOR_COLUMN_NAME: &str = "vector";
@@ -41,6 +42,11 @@ impl std::fmt::Display for Table {
}
}
#[derive(Default)]
pub struct OpenTableParams {
pub open_table_params: ReadParams,
}
impl Table {
/// Opens an existing Table
///
@@ -53,6 +59,25 @@ impl Table {
///
/// * A [Table] object.
pub async fn open(base_uri: &str, name: &str) -> Result<Self> {
Self::open_with_params(base_uri, name, OpenTableParams::default()).await
}
/// Opens an existing Table
///
/// # Arguments
///
/// * `base_path` - The base path where the table is located
/// * `name` The Table name
/// * `params` The [OpenTableParams] to use when opening the table
///
/// # Returns
///
/// * A [Table] object.
pub async fn open_with_params(
base_uri: &str,
name: &str,
params: OpenTableParams,
) -> Result<Self> {
let path = Path::new(base_uri);
let table_uri = path.join(format!("{}.{}", name, LANCE_FILE_EXTENSION));
@@ -61,14 +86,16 @@ impl Table {
.to_str()
.context(InvalidTableNameSnafu { name })?;
let dataset = Dataset::open(&uri).await.map_err(|e| match e {
lance::Error::DatasetNotFound { .. } => Error::TableNotFound {
name: name.to_string(),
},
e => Error::Lance {
message: e.to_string(),
},
})?;
let dataset = Dataset::open_with_params(uri, &params.open_table_params)
.await
.map_err(|e| match e {
lance::Error::DatasetNotFound { .. } => Error::TableNotFound {
name: name.to_string(),
},
e => Error::Lance {
message: e.to_string(),
},
})?;
Ok(Table {
name: name.to_string(),
uri: uri.to_string(),
@@ -91,6 +118,7 @@ impl Table {
base_uri: &str,
name: &str,
mut batches: Box<dyn RecordBatchReader>,
params: Option<WriteParams>,
) -> Result<Self> {
let base_path = Path::new(base_uri);
let table_uri = base_path.join(format!("{}.{}", name, LANCE_FILE_EXTENSION));
@@ -99,7 +127,7 @@ impl Table {
.to_str()
.context(InvalidTableNameSnafu { name })?
.to_string();
let dataset = Dataset::write(&mut batches, &uri, Some(WriteParams::default()))
let dataset = Dataset::write(&mut batches, &uri, params)
.await
.map_err(|e| match e {
lance::Error::DatasetAlreadyExists { .. } => Error::TableAlreadyExists {
@@ -200,17 +228,19 @@ impl Table {
#[cfg(test)]
mod tests {
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use arrow_array::{
Array, FixedSizeListArray, Float32Array, Int32Array, RecordBatch, RecordBatchReader,
Array, FixedSizeListArray, Float32Array, Int32Array, RecordBatch, RecordBatchIterator,
RecordBatchReader,
};
use arrow_data::ArrayDataBuilder;
use arrow_schema::{DataType, Field, Schema};
use lance::arrow::RecordBatchBuffer;
use lance::dataset::{Dataset, WriteMode};
use lance::index::vector::ivf::IvfBuildParams;
use lance::index::vector::pq::PQBuildParams;
use lance::io::object_store::{ObjectStoreParams, WrappingObjectStore};
use rand::Rng;
use tempfile::tempdir;
@@ -223,7 +253,7 @@ mod tests {
let dataset_path = tmp_dir.path().join("test.lance");
let uri = tmp_dir.path().to_str().unwrap();
let mut batches: Box<dyn RecordBatchReader> = Box::new(make_test_batches());
let mut batches: Box<dyn RecordBatchReader> = make_test_batches();
Dataset::write(&mut batches, dataset_path.to_str().unwrap(), None)
.await
.unwrap();
@@ -254,12 +284,12 @@ mod tests {
let tmp_dir = tempdir().unwrap();
let uri = tmp_dir.path().to_str().unwrap();
let batches: Box<dyn RecordBatchReader> = Box::new(make_test_batches());
let batches: Box<dyn RecordBatchReader> = make_test_batches();
let _ = batches.schema().clone();
Table::create(&uri, "test", batches).await.unwrap();
Table::create(&uri, "test", batches, None).await.unwrap();
let batches: Box<dyn RecordBatchReader> = Box::new(make_test_batches());
let result = Table::create(&uri, "test", batches).await;
let batches: Box<dyn RecordBatchReader> = make_test_batches();
let result = Table::create(&uri, "test", batches, None).await;
assert!(matches!(
result.unwrap_err(),
Error::TableAlreadyExists { .. }
@@ -271,17 +301,21 @@ mod tests {
let tmp_dir = tempdir().unwrap();
let uri = tmp_dir.path().to_str().unwrap();
let batches: Box<dyn RecordBatchReader> = Box::new(make_test_batches());
let batches: Box<dyn RecordBatchReader> = make_test_batches();
let schema = batches.schema().clone();
let mut table = Table::create(&uri, "test", batches).await.unwrap();
let mut table = Table::create(&uri, "test", batches, None).await.unwrap();
assert_eq!(table.count_rows().await.unwrap(), 10);
let new_batches: Box<dyn RecordBatchReader> =
Box::new(RecordBatchBuffer::new(vec![RecordBatch::try_new(
schema,
let new_batches: Box<dyn RecordBatchReader> = Box::new(RecordBatchIterator::new(
vec![RecordBatch::try_new(
schema.clone(),
vec![Arc::new(Int32Array::from_iter_values(100..110))],
)
.unwrap()]));
.unwrap()]
.into_iter()
.map(Ok),
schema.clone(),
));
table.add(new_batches, None).await.unwrap();
assert_eq!(table.count_rows().await.unwrap(), 20);
@@ -293,17 +327,21 @@ mod tests {
let tmp_dir = tempdir().unwrap();
let uri = tmp_dir.path().to_str().unwrap();
let batches: Box<dyn RecordBatchReader> = Box::new(make_test_batches());
let batches: Box<dyn RecordBatchReader> = make_test_batches();
let schema = batches.schema().clone();
let mut table = Table::create(uri, "test", batches).await.unwrap();
let mut table = Table::create(uri, "test", batches, None).await.unwrap();
assert_eq!(table.count_rows().await.unwrap(), 10);
let new_batches: Box<dyn RecordBatchReader> =
Box::new(RecordBatchBuffer::new(vec![RecordBatch::try_new(
schema,
let new_batches: Box<dyn RecordBatchReader> = Box::new(RecordBatchIterator::new(
vec![RecordBatch::try_new(
schema.clone(),
vec![Arc::new(Int32Array::from_iter_values(100..110))],
)
.unwrap()]));
.unwrap()]
.into_iter()
.map(Ok),
schema.clone(),
));
table
.add(new_batches, Some(WriteMode::Overwrite))
@@ -319,7 +357,7 @@ mod tests {
let dataset_path = tmp_dir.path().join("test.lance");
let uri = tmp_dir.path().to_str().unwrap();
let mut batches: Box<dyn RecordBatchReader> = Box::new(make_test_batches());
let mut batches: Box<dyn RecordBatchReader> = make_test_batches();
Dataset::write(&mut batches, dataset_path.to_str().unwrap(), None)
.await
.unwrap();
@@ -331,13 +369,63 @@ mod tests {
assert_eq!(vector, query.query_vector);
}
fn make_test_batches() -> RecordBatchBuffer {
#[derive(Default)]
struct NoOpCacheWrapper {
called: AtomicBool,
}
impl NoOpCacheWrapper {
fn called(&self) -> bool {
self.called.load(Ordering::Relaxed)
}
}
impl WrappingObjectStore for NoOpCacheWrapper {
fn wrap(
&self,
original: Arc<dyn object_store::ObjectStore>,
) -> Arc<dyn object_store::ObjectStore> {
self.called.store(true, Ordering::Relaxed);
return original;
}
}
#[tokio::test]
async fn test_open_table_options() {
let tmp_dir = tempdir().unwrap();
let dataset_path = tmp_dir.path().join("test.lance");
let uri = tmp_dir.path().to_str().unwrap();
let mut batches: Box<dyn RecordBatchReader> = make_test_batches();
Dataset::write(&mut batches, dataset_path.to_str().unwrap(), None)
.await
.unwrap();
let wrapper = Arc::new(NoOpCacheWrapper::default());
let mut object_store_params = ObjectStoreParams::default();
object_store_params.object_store_wrapper = Some(wrapper.clone());
let param = OpenTableParams {
open_table_params: ReadParams {
store_options: Some(object_store_params),
..ReadParams::default()
},
};
assert!(!wrapper.called());
let _ = Table::open_with_params(uri, "test", param).await.unwrap();
assert!(wrapper.called());
}
fn make_test_batches() -> Box<dyn RecordBatchReader> {
let schema = Arc::new(Schema::new(vec![Field::new("i", DataType::Int32, false)]));
RecordBatchBuffer::new(vec![RecordBatch::try_new(
schema.clone(),
vec![Arc::new(Int32Array::from_iter_values(0..10))],
)
.unwrap()])
Box::new(RecordBatchIterator::new(
vec![RecordBatch::try_new(
schema.clone(),
vec![Arc::new(Int32Array::from_iter_values(0..10))],
)],
schema,
))
}
#[tokio::test]
@@ -370,14 +458,15 @@ mod tests {
);
let vectors = Arc::new(create_fixed_size_list(float_arr, dimension).unwrap());
let batches = RecordBatchBuffer::new(vec![RecordBatch::try_new(
schema.clone(),
vec![vectors.clone()],
)
.unwrap()]);
let batches = RecordBatchIterator::new(
vec![RecordBatch::try_new(schema.clone(), vec![vectors.clone()]).unwrap()]
.into_iter()
.map(Ok),
schema,
);
let reader: Box<dyn RecordBatchReader + Send> = Box::new(batches);
let mut table = Table::create(uri, "test", reader).await.unwrap();
let mut table = Table::create(uri, "test", reader, None).await.unwrap();
let mut i = IvfPQIndexBuilder::new();