From 30c973e64c5aedb5c08c583a597bdf6f1d18d191 Mon Sep 17 00:00:00 2001 From: Brendan Clement Date: Fri, 9 Oct 2026 17:28:57 -0700 Subject: [PATCH] docs: make the TypeScript and Rust quickstarts complete programs The TypeScript connection example only defined a helper that nothing called, so every later step failed with `db is not defined`. It now connects, as the Python one does. The Rust one kept its connection inside a helper, the Enterprise one read its settings without connecting, and the later steps relied on imports and a record-batch helper the page never showed. The quickstart now says how the steps make one program: an ES module run with Node in TypeScript, and the body of an async `main` in Rust, whose dependencies the install step lists. Each Rust step brings its own imports, the data step shows the helper that turns the records into a reader, and Arrow comes from lancedb's re-exports, so no Arrow crate is needed. The row structs no longer derive serde traits nothing used. The connection examples are shared, so the connect, create-table and branching pages gain the import line their connection code now needs. --- docs/web-tests/rs/connection.rs | 54 +++++++++++++++++------- docs/web-tests/rs/quickstart.rs | 63 ++++++++++++++-------------- docs/web-tests/ts/connection.test.ts | 26 ++++++------ docs/web/basics/connect.mdx | 1 + docs/web/ingestion/create-table.mdx | 2 + docs/web/quickstart.mdx | 27 ++++++++++-- docs/web/snippets/connection.mdx | 6 +-- docs/web/snippets/quickstart.mdx | 14 +++---- docs/web/tables/branching.mdx | 2 + 9 files changed, 122 insertions(+), 73 deletions(-) diff --git a/docs/web-tests/rs/connection.rs b/docs/web-tests/rs/connection.rs index a127c7060..df2cdf30f 100644 --- a/docs/web-tests/rs/connection.rs +++ b/docs/web-tests/rs/connection.rs @@ -3,35 +3,59 @@ use std::path::PathBuf; -use lancedb::connect; +use lancedb::{Connection, connect}; -// --8<-- [start:connect] -async fn connect_example(uri: &str) { - let db = connect(uri).execute().await.unwrap(); - let _ = db; +async fn connect_local() -> lancedb::Result { + // --8<-- [start:connect] + let db = connect("ex_lancedb").execute().await?; + // --8<-- [end:connect] + Ok(db) } -// --8<-- [end:connect] #[tokio::main] -async fn main() { - let temp_dir = tempfile::tempdir().unwrap(); - let uri = temp_dir.path().join("ex_lancedb"); - connect_example(uri.to_str().unwrap()).await; +async fn main() -> Result<(), Box> { + let temp_dir = tempfile::tempdir()?; + std::env::set_current_dir(temp_dir.path())?; + let db = connect_local().await?; + db.create_empty_table( + "probe", + std::sync::Arc::new(arrow_schema::Schema::new(vec![arrow_schema::Field::new( + "id", + arrow_schema::DataType::Int64, + false, + )])), + ) + .execute() + .await?; + let reopened = connect(temp_dir.path().join("ex_lancedb").to_str().unwrap()) + .execute() + .await?; + assert_eq!(reopened.table_names().execute().await?, vec!["probe"]); - // Keep the enterprise snippet in this file, but don't run it in CI. - let _ = connect_enterprise_quickstart_config(); + // Connects to a deployment only when asked, and only lists its tables. + if std::env::var("LANCEDB_DOCS_TEST_DEPLOYMENT").as_deref() == Ok("1") { + let db = connect_enterprise_quickstart().await?; + println!("{:?}", db.table_names().execute().await?); + } let _ = connect_object_storage_config(); + Ok(()) } -fn connect_enterprise_quickstart_config() --> Result<(String, String, String, String), std::env::VarError> { +async fn connect_enterprise_quickstart() -> Result> { // --8<-- [start:connect_enterprise_quickstart] let uri = std::env::var("LANCEDB_URI")?; // db://your-database let api_key = std::env::var("LANCEDB_API_KEY")?; let region = std::env::var("LANCEDB_REGION").unwrap_or_else(|_| "us-east-1".to_string()); let host_override = std::env::var("LANCEDB_HOST_OVERRIDE")?; // https://your-endpoint + + let db = connect(&uri) + .api_key(&api_key) + .region(®ion) + .host_override(&host_override) + .execute() + .await?; // --8<-- [end:connect_enterprise_quickstart] - Ok((uri, api_key, region, host_override)) + Ok(db) } fn connect_object_storage_config() -> &'static str { diff --git a/docs/web-tests/rs/quickstart.rs b/docs/web-tests/rs/quickstart.rs index a279ba562..f6ea7e0f9 100644 --- a/docs/web-tests/rs/quickstart.rs +++ b/docs/web-tests/rs/quickstart.rs @@ -1,23 +1,20 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: Copyright The LanceDB Authors -use std::sync::Arc; - -use arrow_array::types::Float32Type; -use arrow_array::{ - FixedSizeListArray, Int8Array, LargeStringArray, RecordBatch, RecordBatchIterator, StructArray, -}; -use arrow_schema::{DataType, Field, FieldRef, Schema}; -use lancedb::arrow::IntoPolars; -use lancedb::database::CreateTableMode; -use lancedb::query::{ExecutableQuery, QueryBase, Select}; use lancedb::{connect, table::NewColumnTransform}; -use polars::prelude::DataFrame; -use serde::{Deserialize, Serialize}; // --8<-- [start:quickstart_define_struct] +use std::sync::Arc; + +use lancedb::arrow::arrow_array::types::Float32Type; +use lancedb::arrow::arrow_array::{ + FixedSizeListArray, Int8Array, LargeStringArray, RecordBatch, RecordBatchIterator, + RecordBatchReader, StructArray, +}; +use lancedb::arrow::arrow_schema::{DataType, Field, FieldRef, Fields, Schema}; + // Define structs representing the data schema -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone)] struct Stats { strength: i8, magic: i8, @@ -25,7 +22,7 @@ struct Stats { wisdom: i8, } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone)] struct Character { id: String, name: String, @@ -43,7 +40,7 @@ fn characters_schema() -> Arc { Field::new("description", DataType::LargeUtf8, false), Field::new( "stats", - DataType::Struct(arrow_schema::Fields::from(vec![ + DataType::Struct(Fields::from(vec![ Arc::new(Field::new("strength", DataType::Int8, false)), Arc::new(Field::new("magic", DataType::Int8, false)), Arc::new(Field::new("leadership", DataType::Int8, false)), @@ -58,11 +55,11 @@ fn characters_schema() -> Arc { ), ])) } -// --8<-- [end:quickstart_define_struct] -type BatchIter = Box; - -fn characters_to_reader(schema: Arc, rows: &[Character]) -> BatchIter { +fn characters_to_reader( + schema: Arc, + rows: &[Character], +) -> Box { let ids = LargeStringArray::from_iter_values(rows.iter().map(|row| row.id.as_str())); let names = LargeStringArray::from_iter_values(rows.iter().map(|row| row.name.as_str())); let roles = LargeStringArray::from_iter_values(rows.iter().map(|row| row.role.as_str())); @@ -114,6 +111,7 @@ fn characters_to_reader(schema: Arc, rows: &[Character]) -> BatchIter { schema, )) } +// --8<-- [end:quickstart_define_struct] #[tokio::main] async fn main() { @@ -166,6 +164,8 @@ async fn main() { // --8<-- [end:quickstart_data] // --8<-- [start:quickstart_create_table] + use lancedb::database::CreateTableMode; + let schema = characters_schema(); let table = db .create_table("characters", characters_to_reader(schema.clone(), &data)) @@ -199,10 +199,13 @@ async fn main() { assert_eq!(table.count_rows(None).await.unwrap(), 4); // --8<-- [start:quickstart_vector_search_1] + use lancedb::arrow::IntoPolars; + use lancedb::query::{ExecutableQuery, QueryBase, Select}; + // Search for examples similar to a "wise magical advisor" let query_vector = [0.2, 0.8, 0.4, 0.9]; - let result: DataFrame = table + let result = table .query() .nearest_to(&query_vector) .unwrap() @@ -226,7 +229,7 @@ async fn main() { assert_eq!(name_col.get(1).unwrap(), "Morgana"); // --8<-- [start:quickstart_curate_with_metadata] - let curated: DataFrame = table + let curated = table .query() .nearest_to(&query_vector) .unwrap() @@ -251,7 +254,7 @@ async fn main() { assert_eq!(curated_name_col.get(1).unwrap(), "Morgana"); // --8<-- [start:quickstart_output_array] - let result: DataFrame = table + let result = table .query() .nearest_to(&query_vector) .unwrap() @@ -288,7 +291,7 @@ async fn main() { // --8<-- [end:quickstart_add_feature] // --8<-- [start:quickstart_query_feature] - let features: DataFrame = table + let features = table .query() .select(Select::Columns(vec![ "name".to_string(), @@ -317,12 +320,7 @@ async fn main() { std::env::set_current_dir(app.path()).unwrap(); // --8<-- [start:quickstart_multimodal_bytes] - use std::sync::Arc; - - use arrow_array::{ - BinaryArray, FixedSizeListArray, LargeStringArray, RecordBatch, RecordBatchIterator, - }; - use arrow_schema::{DataType, Field, Schema}; + use lancedb::arrow::arrow_array::BinaryArray; let image_bytes = std::fs::read("data/sir-lancelot.jpg").unwrap(); @@ -356,9 +354,10 @@ async fn main() { ], ) .unwrap(); - let image_reader: Box = Box::new( - RecordBatchIterator::new(vec![Ok(image_batch)].into_iter(), image_schema), - ); + let image_reader: Box = Box::new(RecordBatchIterator::new( + vec![Ok(image_batch)].into_iter(), + image_schema, + )); let multimodal_table = db .create_table("character_images", image_reader) .mode(CreateTableMode::Overwrite) diff --git a/docs/web-tests/ts/connection.test.ts b/docs/web-tests/ts/connection.test.ts index e1574976c..ac1ff68a1 100644 --- a/docs/web-tests/ts/connection.test.ts +++ b/docs/web-tests/ts/connection.test.ts @@ -1,22 +1,24 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: Copyright The LanceDB Authors import { afterEach, describe, expect, jest, test } from "@jest/globals"; -import * as path from "node:path"; -import { withTempDirectory } from "./util.ts"; -// --8<-- [start:connect] import * as lancedb from "@lancedb/lancedb"; - -async function connectExample(uri: string) { - const db = await lancedb.connect(uri); - return db; -} -// --8<-- [end:connect] +import { withTempDirectory } from "./util.ts"; test("connect to a local database", async () => { await withTempDirectory(async (tempDir) => { - const uri = path.join(tempDir, "ex_lancedb"); - const db = await connectExample(uri); - expect(db).toBeDefined(); + const cwd = process.cwd(); + process.chdir(tempDir); + try { + // --8<-- [start:connect] + const db = await lancedb.connect("ex_lancedb"); + // --8<-- [end:connect] + await db.createTable("probe", [{ id: 1 }]); + expect((await db.listTables()).tables).toEqual(["probe"]); + } finally { + process.chdir(cwd); + } + const reopened = await lancedb.connect(`${tempDir}/ex_lancedb`); + expect((await reopened.listTables()).tables).toEqual(["probe"]); }); }); diff --git a/docs/web/basics/connect.mdx b/docs/web/basics/connect.mdx index 4ec5aa599..3ecbd5335 100644 --- a/docs/web/basics/connect.mdx +++ b/docs/web/basics/connect.mdx @@ -43,6 +43,7 @@ directory on disk. + { "import * as lancedb from \"@lancedb/lancedb\";\n\n" } {TsConnect} diff --git a/docs/web/ingestion/create-table.mdx b/docs/web/ingestion/create-table.mdx index ff431107c..86195df20 100644 --- a/docs/web/ingestion/create-table.mdx +++ b/docs/web/ingestion/create-table.mdx @@ -64,10 +64,12 @@ Initialize a LanceDB connection and create a table. A table's name follows the + { "import * as lancedb from \"@lancedb/lancedb\";\n\n" } {TsConnect} + { "use lancedb::connect;\n\n" } {RsConnect} diff --git a/docs/web/quickstart.mdx b/docs/web/quickstart.mdx index 157e5e58d..de4b8e1f3 100644 --- a/docs/web/quickstart.mdx +++ b/docs/web/quickstart.mdx @@ -79,10 +79,27 @@ npm install @lancedb/lancedb ``` ```bash Rust icon=Rust -cargo add lancedb +cargo add lancedb --features polars,remote +cargo add tokio --features macros,rt-multi-thread ``` +The TypeScript and Rust code of steps 2 to 5 makes one program. In TypeScript, +put it, in order, in an ES module such as `quickstart.mts` and run +`node quickstart.mts`; Node.js 22.18 and later run TypeScript directly. In Rust, +it goes, in order, inside `main` in `src/main.rs`, and `cargo run` runs it. The +`polars` feature returns results as DataFrames, and `remote` connects to +LanceDB Enterprise. + +```rust src/main.rs icon="rust" +#[tokio::main] +async fn main() -> Result<(), Box> { + // The Rust code of steps 2 to 5 goes here. + + Ok(()) +} +``` + ### Python pre-release builds {#python-pre-release-builds} To pick up the latest features and bug fixes @@ -149,6 +166,7 @@ client SDK of choice and point to a local directory path. + { "import * as lancedb from \"@lancedb/lancedb\";\n\n" } {TsConnect} @@ -213,12 +231,12 @@ endpoint is required: without it the code stops rather than guessing one. + { "use lancedb::connect;\n\n" } {RsConnectEnterpriseQuickstart} -In Rust, pass the same settings to the connection builder's `api_key`, `region` -and `host_override`. A deployment runs some things differently -- maintenance, +A deployment runs some things differently -- maintenance, long-running work, a few unsupported methods; see [Moving to LanceDB Enterprise](/basics/sdk#moving-to-enterprise), and the [Enterprise overview](/enterprise) for how a deployment is put together. @@ -371,7 +389,8 @@ deployment. ## Optional extensions {#extensions} Each extension below starts from the `characters` table of step 3 and stands on its own, -so take any of them, in any order, or none. +so take any of them, in any order, or none. In TypeScript and Rust, its code goes after +step 5's. ### Add a derived feature {#6-add-a-derived-feature} diff --git a/docs/web/snippets/connection.mdx b/docs/web/snippets/connection.mdx index c895f5323..eb1a94a9e 100644 --- a/docs/web/snippets/connection.mdx +++ b/docs/web/snippets/connection.mdx @@ -14,7 +14,7 @@ export const PyNamespaceAdminOps = "import lancedb\n\ndb = lancedb.connect_names export const PyNamespaceTableOps = "import lancedb\n\ndb = lancedb.connect_namespace(\"dir\", {\"root\": \"./local_lancedb\"})\n\n# Create namespace tree: prod/search\ndb.create_namespace([\"prod\"], mode=\"exist_ok\")\ndb.create_namespace([\"prod\", \"search\"], mode=\"exist_ok\")\ndb.create_namespace([\"prod\", \"recommendations\"], mode=\"exist_ok\")\n\ndb.create_table(\n \"user\",\n data=[{\"id\": 1, \"vector\": [0.1, 0.2], \"name\": \"alice\"}],\n namespace_path=[\"prod\", \"search\"],\n mode=\"create\", # use \"overwrite\" only if you want to replace existing table\n)\n\ndb.create_table(\n \"user\",\n data=[{\"id\": 2, \"vector\": [0.3, 0.4], \"name\": \"bob\"}],\n namespace_path=[\"prod\", \"recommendations\"],\n mode=\"create\", # use \"overwrite\" only if you want to replace existing table\n)\n\n# Verify: listings return a response with the names and a page token\nprint(db.list_namespaces().namespaces) # ['prod']\nprint(db.list_namespaces(namespace_path=[\"prod\"]).namespaces)\n# ['recommendations', 'search']\nprint(db.list_tables(namespace_path=[\"prod\", \"search\"]).tables) # ['user']\nprint(db.list_tables(namespace_path=[\"prod\", \"recommendations\"]).tables) # ['user']\n"; -export const TsConnect = "import * as lancedb from \"@lancedb/lancedb\";\n\nasync function connectExample(uri: string) {\n const db = await lancedb.connect(uri);\n return db;\n}\n"; +export const TsConnect = "const db = await lancedb.connect(\"ex_lancedb\");\n"; export const TsConnectEnterpriseQuickstart = "const setting = (name: string) => {\n const value = process.env[name];\n if (!value) throw new Error(`Set ${name}`);\n return value;\n};\n\nconst db = await lancedb.connect(setting(\"LANCEDB_URI\"), {\n apiKey: setting(\"LANCEDB_API_KEY\"),\n region: process.env.LANCEDB_REGION ?? \"us-east-1\",\n hostOverride: setting(\"LANCEDB_HOST_OVERRIDE\"),\n});\n"; @@ -24,9 +24,9 @@ export const TsNamespaceAdminOps = "const db = await lancedb.connectNamespace(\" export const TsNamespaceTableOps = "const db = await lancedb.connectNamespace(\"dir\", { root: \"./local_lancedb\" });\n\n// Create namespace tree: prod/search and prod/recommendations\nawait db.createNamespace([\"prod\"], { mode: \"exist_ok\" });\nawait db.createNamespace([\"prod\", \"search\"], { mode: \"exist_ok\" });\nawait db.createNamespace([\"prod\", \"recommendations\"], { mode: \"exist_ok\" });\n\nawait db.createTable(\n \"user\",\n [{ id: 1, vector: [0.1, 0.2], name: \"alice\" }],\n [\"prod\", \"search\"],\n { mode: \"create\" }, // use \"overwrite\" only if you want to replace existing table\n);\n\nawait db.createTable(\n \"user\",\n [{ id: 2, vector: [0.3, 0.4], name: \"bob\" }],\n [\"prod\", \"recommendations\"],\n { mode: \"create\" },\n);\n\n// Verify\nconsole.log((await db.listNamespaces()).namespaces); // [\"prod\"]\nconsole.log((await db.listNamespaces([\"prod\"])).namespaces); // [\"recommendations\", \"search\"]\nconsole.log(await db.tableNames([\"prod\", \"search\"])); // [\"user\"]\nconsole.log(await db.tableNames([\"prod\", \"recommendations\"])); // [\"user\"]\n"; -export const RsConnect = "async fn connect_example(uri: &str) {\n let db = connect(uri).execute().await.unwrap();\n let _ = db;\n}\n"; +export const RsConnect = "let db = connect(\"ex_lancedb\").execute().await?;\n"; -export const RsConnectEnterpriseQuickstart = "let uri = std::env::var(\"LANCEDB_URI\")?; // db://your-database\nlet api_key = std::env::var(\"LANCEDB_API_KEY\")?;\nlet region = std::env::var(\"LANCEDB_REGION\").unwrap_or_else(|_| \"us-east-1\".to_string());\nlet host_override = std::env::var(\"LANCEDB_HOST_OVERRIDE\")?; // https://your-endpoint\n"; +export const RsConnectEnterpriseQuickstart = "let uri = std::env::var(\"LANCEDB_URI\")?; // db://your-database\nlet api_key = std::env::var(\"LANCEDB_API_KEY\")?;\nlet region = std::env::var(\"LANCEDB_REGION\").unwrap_or_else(|_| \"us-east-1\".to_string());\nlet host_override = std::env::var(\"LANCEDB_HOST_OVERRIDE\")?; // https://your-endpoint\n\nlet db = connect(&uri)\n .api_key(&api_key)\n .region(®ion)\n .host_override(&host_override)\n .execute()\n .await?;\n"; export const RsConnectObjectStorage = "let uri = \"s3://your-bucket/path\";\n// You can also use \"gs://your-bucket/path\" or \"az://your-container/path\".\n"; diff --git a/docs/web/snippets/quickstart.mdx b/docs/web/snippets/quickstart.mdx index 5c8dcb6b5..c7cf98e32 100644 --- a/docs/web/snippets/quickstart.mdx +++ b/docs/web/snippets/quickstart.mdx @@ -48,19 +48,19 @@ export const RsQuickstartAddData = "let more_data = vec![Character {\n id: \" export const RsQuickstartAddFeature = "table\n .add_columns(\n NewColumnTransform::SqlExpressions(vec![(\n \"power_score\".to_string(),\n \"cast(((stats.strength + stats.magic + stats.leadership + stats.wisdom) / 4.0) as float)\"\n .to_string(),\n )]),\n None,\n )\n .await\n .unwrap();\n"; -export const RsQuickstartCreateTable = "let schema = characters_schema();\nlet table = db\n .create_table(\"characters\", characters_to_reader(schema.clone(), &data))\n .mode(CreateTableMode::Overwrite)\n .execute()\n .await\n .unwrap();\n"; +export const RsQuickstartCreateTable = "use lancedb::database::CreateTableMode;\n\nlet schema = characters_schema();\nlet table = db\n .create_table(\"characters\", characters_to_reader(schema.clone(), &data))\n .mode(CreateTableMode::Overwrite)\n .execute()\n .await\n .unwrap();\n"; -export const RsQuickstartCurateWithMetadata = "let curated: DataFrame = table\n .query()\n .nearest_to(&query_vector)\n .unwrap()\n .only_if(\"stats.magic >= 4\")\n .select(Select::Columns(vec![\n \"name\".to_string(),\n \"role\".to_string(),\n \"description\".to_string(),\n \"_distance\".to_string(),\n ]))\n .limit(2)\n .execute()\n .await\n .unwrap()\n .into_polars()\n .await\n .unwrap();\nprintln!(\"{curated:?}\");\n"; +export const RsQuickstartCurateWithMetadata = "let curated = table\n .query()\n .nearest_to(&query_vector)\n .unwrap()\n .only_if(\"stats.magic >= 4\")\n .select(Select::Columns(vec![\n \"name\".to_string(),\n \"role\".to_string(),\n \"description\".to_string(),\n \"_distance\".to_string(),\n ]))\n .limit(2)\n .execute()\n .await\n .unwrap()\n .into_polars()\n .await\n .unwrap();\nprintln!(\"{curated:?}\");\n"; export const RsQuickstartData = "let data = vec![\n Character {\n id: \"1\".to_string(),\n name: \"King Arthur\".to_string(),\n role: \"King\".to_string(),\n description: \"Leader of Camelot and wielder of Excalibur.\".to_string(),\n stats: Stats {\n strength: 4,\n magic: 1,\n leadership: 5,\n wisdom: 4,\n },\n vector: [0.7, 0.1, 0.9, 0.7],\n },\n Character {\n id: \"2\".to_string(),\n name: \"Merlin\".to_string(),\n role: \"Wizard\".to_string(),\n description: \"Advisor and prophet with deep magical knowledge.\".to_string(),\n stats: Stats {\n strength: 2,\n magic: 5,\n leadership: 4,\n wisdom: 5,\n },\n vector: [0.2, 0.9, 0.4, 0.9],\n },\n Character {\n id: \"3\".to_string(),\n name: \"Sir Lancelot\".to_string(),\n role: \"Knight\".to_string(),\n description: \"Legendary knight known for courage and combat skill.\".to_string(),\n stats: Stats {\n strength: 5,\n magic: 1,\n leadership: 3,\n wisdom: 3,\n },\n vector: [0.9, 0.1, 0.5, 0.4],\n },\n];\n"; -export const RsQuickstartDefineStruct = "// Define structs representing the data schema\n#[derive(Debug, Clone, Serialize, Deserialize)]\nstruct Stats {\n strength: i8,\n magic: i8,\n leadership: i8,\n wisdom: i8,\n}\n\n#[derive(Debug, Clone, Serialize, Deserialize)]\nstruct Character {\n id: String,\n name: String,\n role: String,\n description: String,\n stats: Stats,\n vector: [f32; 4],\n}\n\nfn characters_schema() -> Arc {\n Arc::new(Schema::new(vec![\n Field::new(\"id\", DataType::LargeUtf8, false),\n Field::new(\"name\", DataType::LargeUtf8, false),\n Field::new(\"role\", DataType::LargeUtf8, false),\n Field::new(\"description\", DataType::LargeUtf8, false),\n Field::new(\n \"stats\",\n DataType::Struct(arrow_schema::Fields::from(vec![\n Arc::new(Field::new(\"strength\", DataType::Int8, false)),\n Arc::new(Field::new(\"magic\", DataType::Int8, false)),\n Arc::new(Field::new(\"leadership\", DataType::Int8, false)),\n Arc::new(Field::new(\"wisdom\", DataType::Int8, false)),\n ])),\n false,\n ),\n Field::new(\n \"vector\",\n DataType::FixedSizeList(Arc::new(Field::new(\"item\", DataType::Float32, true)), 4),\n false,\n ),\n ]))\n}\n"; +export const RsQuickstartDefineStruct = "use std::sync::Arc;\n\nuse lancedb::arrow::arrow_array::types::Float32Type;\nuse lancedb::arrow::arrow_array::{\n FixedSizeListArray, Int8Array, LargeStringArray, RecordBatch, RecordBatchIterator,\n RecordBatchReader, StructArray,\n};\nuse lancedb::arrow::arrow_schema::{DataType, Field, FieldRef, Fields, Schema};\n\n// Define structs representing the data schema\n#[derive(Debug, Clone)]\nstruct Stats {\n strength: i8,\n magic: i8,\n leadership: i8,\n wisdom: i8,\n}\n\n#[derive(Debug, Clone)]\nstruct Character {\n id: String,\n name: String,\n role: String,\n description: String,\n stats: Stats,\n vector: [f32; 4],\n}\n\nfn characters_schema() -> Arc {\n Arc::new(Schema::new(vec![\n Field::new(\"id\", DataType::LargeUtf8, false),\n Field::new(\"name\", DataType::LargeUtf8, false),\n Field::new(\"role\", DataType::LargeUtf8, false),\n Field::new(\"description\", DataType::LargeUtf8, false),\n Field::new(\n \"stats\",\n DataType::Struct(Fields::from(vec![\n Arc::new(Field::new(\"strength\", DataType::Int8, false)),\n Arc::new(Field::new(\"magic\", DataType::Int8, false)),\n Arc::new(Field::new(\"leadership\", DataType::Int8, false)),\n Arc::new(Field::new(\"wisdom\", DataType::Int8, false)),\n ])),\n false,\n ),\n Field::new(\n \"vector\",\n DataType::FixedSizeList(Arc::new(Field::new(\"item\", DataType::Float32, true)), 4),\n false,\n ),\n ]))\n}\n\nfn characters_to_reader(\n schema: Arc,\n rows: &[Character],\n) -> Box {\n let ids = LargeStringArray::from_iter_values(rows.iter().map(|row| row.id.as_str()));\n let names = LargeStringArray::from_iter_values(rows.iter().map(|row| row.name.as_str()));\n let roles = LargeStringArray::from_iter_values(rows.iter().map(|row| row.role.as_str()));\n let descriptions =\n LargeStringArray::from_iter_values(rows.iter().map(|row| row.description.as_str()));\n\n let strength = Int8Array::from_iter_values(rows.iter().map(|row| row.stats.strength));\n let magic = Int8Array::from_iter_values(rows.iter().map(|row| row.stats.magic));\n let leadership = Int8Array::from_iter_values(rows.iter().map(|row| row.stats.leadership));\n let wisdom = Int8Array::from_iter_values(rows.iter().map(|row| row.stats.wisdom));\n let stats_fields: Vec = vec![\n Arc::new(Field::new(\"strength\", DataType::Int8, false)),\n Arc::new(Field::new(\"magic\", DataType::Int8, false)),\n Arc::new(Field::new(\"leadership\", DataType::Int8, false)),\n Arc::new(Field::new(\"wisdom\", DataType::Int8, false)),\n ];\n let stats = StructArray::new(\n stats_fields.into(),\n vec![\n Arc::new(strength),\n Arc::new(magic),\n Arc::new(leadership),\n Arc::new(wisdom),\n ],\n None,\n );\n\n let vectors = FixedSizeListArray::from_iter_primitive::(\n rows.iter()\n .map(|row| Some(row.vector.iter().copied().map(Some).collect::>())),\n 4,\n );\n\n let batch = RecordBatch::try_new(\n schema.clone(),\n vec![\n Arc::new(ids),\n Arc::new(names),\n Arc::new(roles),\n Arc::new(descriptions),\n Arc::new(stats),\n Arc::new(vectors),\n ],\n )\n .unwrap();\n\n Box::new(RecordBatchIterator::new(\n vec![Ok(batch)].into_iter(),\n schema,\n ))\n}\n"; -export const RsQuickstartMultimodalBytes = "use std::sync::Arc;\n\nuse arrow_array::{\n BinaryArray, FixedSizeListArray, LargeStringArray, RecordBatch, RecordBatchIterator,\n};\nuse arrow_schema::{DataType, Field, Schema};\n\nlet image_bytes = std::fs::read(\"data/sir-lancelot.jpg\").unwrap();\n\nlet image_schema = Arc::new(Schema::new(vec![\n Field::new(\"id\", DataType::LargeUtf8, false),\n Field::new(\"description\", DataType::LargeUtf8, false),\n Field::new(\"image\", DataType::Binary, false),\n Field::new(\n \"vector\",\n DataType::FixedSizeList(Arc::new(Field::new(\"item\", DataType::Float32, true)), 4),\n false,\n ),\n]));\nlet image_vectors = [[0.9_f32, 0.1, 0.5, 0.4]];\nlet image_batch = RecordBatch::try_new(\n image_schema.clone(),\n vec![\n Arc::new(LargeStringArray::from_iter_values([\"lancelot\"])),\n Arc::new(LargeStringArray::from_iter_values([\n \"Portrait of Sir Lancelot\",\n ])),\n Arc::new(BinaryArray::from_iter_values([image_bytes.as_slice()])),\n Arc::new(\n FixedSizeListArray::from_iter_primitive::(\n image_vectors\n .iter()\n .map(|vector| Some(vector.iter().copied().map(Some).collect::>())),\n 4,\n ),\n ),\n ],\n)\n.unwrap();\nlet image_reader: Box = Box::new(\n RecordBatchIterator::new(vec![Ok(image_batch)].into_iter(), image_schema),\n);\nlet multimodal_table = db\n .create_table(\"character_images\", image_reader)\n .mode(CreateTableMode::Overwrite)\n .execute()\n .await\n .unwrap();\n"; +export const RsQuickstartMultimodalBytes = "use lancedb::arrow::arrow_array::BinaryArray;\n\nlet image_bytes = std::fs::read(\"data/sir-lancelot.jpg\").unwrap();\n\nlet image_schema = Arc::new(Schema::new(vec![\n Field::new(\"id\", DataType::LargeUtf8, false),\n Field::new(\"description\", DataType::LargeUtf8, false),\n Field::new(\"image\", DataType::Binary, false),\n Field::new(\n \"vector\",\n DataType::FixedSizeList(Arc::new(Field::new(\"item\", DataType::Float32, true)), 4),\n false,\n ),\n]));\nlet image_vectors = [[0.9_f32, 0.1, 0.5, 0.4]];\nlet image_batch = RecordBatch::try_new(\n image_schema.clone(),\n vec![\n Arc::new(LargeStringArray::from_iter_values([\"lancelot\"])),\n Arc::new(LargeStringArray::from_iter_values([\n \"Portrait of Sir Lancelot\",\n ])),\n Arc::new(BinaryArray::from_iter_values([image_bytes.as_slice()])),\n Arc::new(\n FixedSizeListArray::from_iter_primitive::(\n image_vectors\n .iter()\n .map(|vector| Some(vector.iter().copied().map(Some).collect::>())),\n 4,\n ),\n ),\n ],\n)\n.unwrap();\nlet image_reader: Box = Box::new(RecordBatchIterator::new(\n vec![Ok(image_batch)].into_iter(),\n image_schema,\n));\nlet multimodal_table = db\n .create_table(\"character_images\", image_reader)\n .mode(CreateTableMode::Overwrite)\n .execute()\n .await\n .unwrap();\n"; -export const RsQuickstartOutputArray = "let result: DataFrame = table\n .query()\n .nearest_to(&query_vector)\n .unwrap()\n .select(Select::Columns(vec![\n \"name\".to_string(),\n \"role\".to_string(),\n \"description\".to_string(),\n \"_distance\".to_string(),\n ]))\n .limit(2)\n .execute()\n .await\n .unwrap()\n .into_polars()\n .await\n .unwrap();\nprintln!(\"{result:?}\");\n"; +export const RsQuickstartOutputArray = "let result = table\n .query()\n .nearest_to(&query_vector)\n .unwrap()\n .select(Select::Columns(vec![\n \"name\".to_string(),\n \"role\".to_string(),\n \"description\".to_string(),\n \"_distance\".to_string(),\n ]))\n .limit(2)\n .execute()\n .await\n .unwrap()\n .into_polars()\n .await\n .unwrap();\nprintln!(\"{result:?}\");\n"; -export const RsQuickstartQueryFeature = "let features: DataFrame = table\n .query()\n .select(Select::Columns(vec![\n \"name\".to_string(),\n \"role\".to_string(),\n \"power_score\".to_string(),\n ]))\n .execute()\n .await\n .unwrap()\n .into_polars()\n .await\n .unwrap();\nprintln!(\"{features:?}\");\n"; +export const RsQuickstartQueryFeature = "let features = table\n .query()\n .select(Select::Columns(vec![\n \"name\".to_string(),\n \"role\".to_string(),\n \"power_score\".to_string(),\n ]))\n .execute()\n .await\n .unwrap()\n .into_polars()\n .await\n .unwrap();\nprintln!(\"{features:?}\");\n"; -export const RsQuickstartVectorSearch1 = "// Search for examples similar to a \"wise magical advisor\"\nlet query_vector = [0.2, 0.8, 0.4, 0.9];\n\nlet result: DataFrame = table\n .query()\n .nearest_to(&query_vector)\n .unwrap()\n .select(Select::Columns(vec![\n \"name\".to_string(),\n \"role\".to_string(),\n \"description\".to_string(),\n \"_distance\".to_string(),\n ]))\n .limit(2)\n .execute()\n .await\n .unwrap()\n .into_polars()\n .await\n .unwrap();\nprintln!(\"{result:?}\");\n"; +export const RsQuickstartVectorSearch1 = "use lancedb::arrow::IntoPolars;\nuse lancedb::query::{ExecutableQuery, QueryBase, Select};\n\n// Search for examples similar to a \"wise magical advisor\"\nlet query_vector = [0.2, 0.8, 0.4, 0.9];\n\nlet result = table\n .query()\n .nearest_to(&query_vector)\n .unwrap()\n .select(Select::Columns(vec![\n \"name\".to_string(),\n \"role\".to_string(),\n \"description\".to_string(),\n \"_distance\".to_string(),\n ]))\n .limit(2)\n .execute()\n .await\n .unwrap()\n .into_polars()\n .await\n .unwrap();\nprintln!(\"{result:?}\");\n"; diff --git a/docs/web/tables/branching.mdx b/docs/web/tables/branching.mdx index 25defcd38..19f08a343 100644 --- a/docs/web/tables/branching.mdx +++ b/docs/web/tables/branching.mdx @@ -85,6 +85,7 @@ embedded library. + { "import * as lancedb from \"@lancedb/lancedb\";\n\n" } {TsConnect} @@ -114,6 +115,7 @@ every example that follows. + { "use lancedb::connect;\n\n" } {RsConnectEnterpriseQuickstart}