Skip to content

Commit ffb94f6

Browse files
Merge pull request #117 from theseus-rs/add-portal-corp-example
docs: add PortalCorp example for pgvector
2 parents afac84f + d69f829 commit ffb94f6

File tree

6 files changed

+190
-20
lines changed

6 files changed

+190
-20
lines changed

Cargo.lock

Lines changed: 38 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ human_bytes = { version = "0.4.3", default-features = false }
3636
indoc = "2.0.5"
3737
md-5 = "0.10.6"
3838
num-format = "0.4.4"
39+
pgvector = "0.4.0"
3940
quick-xml = "0.36.1"
4041
rand = "0.8.5"
4142
regex = "1.10.6"
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[package]
2+
edition.workspace = true
3+
name = "portal_corp_extension"
4+
publish = false
5+
license.workspace = true
6+
version.workspace = true
7+
8+
[dependencies]
9+
anyhow = { workspace = true }
10+
indoc = { workspace = true }
11+
pgvector = { workspace = true, features = ["sqlx"] }
12+
postgresql_embedded = { path = "../../postgresql_embedded" }
13+
postgresql_extensions = { path = "../../postgresql_extensions" }
14+
sqlx = { workspace = true, features = ["runtime-tokio"] }
15+
tracing = { workspace = true }
16+
tracing-subscriber = { workspace = true }
17+
tokio = { workspace = true, features = ["full"] }
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
#![forbid(unsafe_code)]
2+
#![deny(clippy::pedantic)]
3+
4+
use anyhow::Result;
5+
use indoc::indoc;
6+
use pgvector::Vector;
7+
use sqlx::{PgPool, Row};
8+
use tracing::info;
9+
10+
use postgresql_embedded::{PostgreSQL, Settings, VersionReq};
11+
12+
/// Example of how to install and configure the PortalCorp pgvector extension.
13+
///
14+
/// See: <https://github.com/pgvector/pgvector?tab=readme-ov-file#getting-started>
15+
#[tokio::main]
16+
async fn main() -> Result<()> {
17+
tracing_subscriber::fmt().compact().init();
18+
19+
info!("Installing PostgreSQL");
20+
let settings = Settings {
21+
version: VersionReq::parse("=16.3.0")?,
22+
..Default::default()
23+
};
24+
let mut postgresql = PostgreSQL::new(settings);
25+
postgresql.setup().await?;
26+
27+
info!("Installing the vector extension from PortalCorp");
28+
postgresql_extensions::install(
29+
postgresql.settings(),
30+
"portal-corp",
31+
"pgvector_compiled",
32+
&VersionReq::parse("=0.16.12")?,
33+
)
34+
.await?;
35+
36+
info!("Starting PostgreSQL");
37+
postgresql.start().await?;
38+
39+
let database_name = "vector-example";
40+
info!("Creating database {database_name}");
41+
postgresql.create_database(database_name).await?;
42+
43+
info!("Configuring extension");
44+
let settings = postgresql.settings();
45+
let database_url = settings.url(database_name);
46+
let pool = PgPool::connect(database_url.as_str()).await?;
47+
pool.close().await;
48+
49+
info!("Restarting database");
50+
postgresql.stop().await?;
51+
postgresql.start().await?;
52+
53+
info!("Enabling extension");
54+
let pool = PgPool::connect(database_url.as_str()).await?;
55+
enable_extension(&pool).await?;
56+
57+
info!("Creating table");
58+
create_table(&pool).await?;
59+
60+
info!("Creating data");
61+
create_data(&pool).await?;
62+
63+
info!("Get the nearest neighbors by L2 distance");
64+
execute_query(
65+
&pool,
66+
"SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 5",
67+
)
68+
.await?;
69+
70+
info!("Stopping database");
71+
postgresql.stop().await?;
72+
Ok(())
73+
}
74+
75+
async fn enable_extension(pool: &PgPool) -> Result<()> {
76+
sqlx::query("DROP EXTENSION IF EXISTS vector")
77+
.execute(pool)
78+
.await?;
79+
sqlx::query("CREATE EXTENSION IF NOT EXISTS vector")
80+
.execute(pool)
81+
.await?;
82+
Ok(())
83+
}
84+
85+
async fn create_table(pool: &PgPool) -> Result<()> {
86+
sqlx::query(indoc! {"
87+
CREATE TABLE IF NOT EXISTS items (
88+
id bigserial PRIMARY KEY,
89+
embedding vector(3) NOT NULL
90+
)
91+
"})
92+
.execute(pool)
93+
.await?;
94+
Ok(())
95+
}
96+
97+
async fn create_data(pool: &PgPool) -> Result<()> {
98+
sqlx::query(indoc! {"
99+
INSERT INTO items (embedding)
100+
VALUES
101+
('[1,2,3]'),
102+
('[4,5,6]')
103+
"})
104+
.execute(pool)
105+
.await?;
106+
Ok(())
107+
}
108+
109+
async fn execute_query(pool: &PgPool, query: &str) -> Result<()> {
110+
info!("Query: {query}");
111+
let rows = sqlx::query(query).fetch_all(pool).await?;
112+
for row in rows {
113+
let id: i64 = row.try_get("id")?;
114+
let embedding: Vector = row.try_get("embedding")?;
115+
info!("ID: {id}, Embedding: {embedding:?}");
116+
}
117+
Ok(())
118+
}
119+
120+
#[cfg(test)]
121+
mod test {
122+
use super::*;
123+
124+
#[test]
125+
fn test_main() -> Result<()> {
126+
main()
127+
}
128+
}

examples/vector_extension/Cargo.toml renamed to examples/tensor_chord_extension/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
edition.workspace = true
3-
name = "vector_extension"
3+
name = "tensor_chord_extension"
44
publish = false
55
license.workspace = true
66
version.workspace = true

examples/vector_extension/src/main.rs renamed to examples/tensor_chord_extension/src/main.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use tracing::info;
88

99
use postgresql_embedded::{PostgreSQL, Settings, VersionReq};
1010

11-
/// Example of how to install and configure the vector extension.
11+
/// Example of how to install and configure the TensorChord vector extension.
1212
///
1313
/// See: <https://github.com/tensorchord/pgvecto.rs/?tab=readme-ov-file#quick-start>
1414
#[tokio::main]
@@ -63,21 +63,21 @@ async fn main() -> Result<()> {
6363
info!("Squared Euclidean Distance");
6464
execute_query(
6565
&pool,
66-
"SELECT '[1, 2, 3]'::vector <-> '[3, 2, 1]'::vector AS value;",
66+
"SELECT '[1, 2, 3]'::vector <-> '[3, 2, 1]'::vector AS value",
6767
)
6868
.await?;
6969

7070
info!("Negative Dot Product");
7171
execute_query(
7272
&pool,
73-
"SELECT '[1, 2, 3]'::vector <#> '[3, 2, 1]'::vector AS value;",
73+
"SELECT '[1, 2, 3]'::vector <#> '[3, 2, 1]'::vector AS value",
7474
)
7575
.await?;
7676

7777
info!("Cosine Distance");
7878
execute_query(
7979
&pool,
80-
"SELECT '[1, 2, 3]'::vector <=> '[3, 2, 1]'::vector AS value;",
80+
"SELECT '[1, 2, 3]'::vector <=> '[3, 2, 1]'::vector AS value",
8181
)
8282
.await?;
8383

@@ -100,7 +100,7 @@ async fn enable_extension(pool: &PgPool) -> Result<()> {
100100
sqlx::query("DROP EXTENSION IF EXISTS vectors")
101101
.execute(pool)
102102
.await?;
103-
sqlx::query("CREATE EXTENSION vectors")
103+
sqlx::query("CREATE EXTENSION IF NOT EXISTS vectors")
104104
.execute(pool)
105105
.await?;
106106
Ok(())

0 commit comments

Comments
 (0)