MCPcopy Index your code
hub / github.com/XiangpengHao/pq-vector

github.com/XiangpengHao/pq-vector @main

Chat with this repo
repository ↗ · DeepWiki ↗ · + Follow
203 symbols 417 edges 21 files 7 documented · 3%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

pq-vector

CI

Vector Search with only Parquet and DataFusion

Features

  • Embedded Index: Index stored within the Parquet file itself - no separate index files
  • Standard Compatible: Indexed files remain valid Parquet - DuckDB, Pandas, etc. can read them normally
  • DataFusion integration: Ergonomic vector search with just SQL.
  • Zero-copy: Zero-copy, in-place Parquet indexing.

Quick start

1) Build an index

use pq_vector::IndexBuilder;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    IndexBuilder::new(
        "data/embeddings.parquet", // Source file (indexed in-place by default)
        "embedding",               // Column name containing vectors
    )
    .n_clusters(100)
    .max_iters(20)
    .seed(42)
    .build_inplace()?;

    // Optional: write to a new file instead of in-place
    IndexBuilder::new("data/embeddings.parquet", "embedding")
        .build_new("data/embeddings_indexed.parquet")?;

    Ok(())
}

2) Search with Rust

use pq_vector::TopkBuilder;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let query_vector: Vec<f32> = vec![/* your query embedding */];

    let results = TopkBuilder::new("data/embeddings_indexed.parquet", &query_vector)
    .k(10)?
    .nprobe(5)?
    .search()
    .await?;

    for result in results {
        println!("Row {}: distance {:.4}", result.row_idx, result.distance);
    }

    Ok(())
}

3) DataFusion SQL

use datafusion::execution::SessionStateBuilder;
use datafusion::prelude::{ParquetReadOptions, SessionContext};
use pq_vector::df_vector::{PqVectorSessionBuilderExt, VectorTopKOptions};
use pq_vector::IndexBuilder;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let indexed = "data/embeddings_indexed.parquet";

    let options = VectorTopKOptions {
        nprobe: 8,
        max_candidates: None,
    };
    let state = SessionStateBuilder::new()
        .with_default_features()
        .with_pq_vector(options) // ENABLE pq-vector here!
        .build();
    let ctx = SessionContext::new_with_state(state);

    ctx.register_parquet("t", indexed, ParquetReadOptions::default())
        .await?;

    let df = ctx
        .sql(
            r#"
            SELECT id
            FROM t
            WHERE id >= 100
            ORDER BY array_distance(embedding, [0.0, 0.0])
            LIMIT 5
            "#,
        )
        .await?;
    let _batches = df.collect().await?;
    Ok(())
}

If you already have a custom SessionConfig, enable pq-vector like this:

use datafusion::execution::SessionStateBuilder;
use datafusion::prelude::SessionConfig;
use pq_vector::df_vector::{PqVectorSessionBuilderExt, PqVectorSessionConfigExt, VectorTopKOptions};

let options = VectorTopKOptions {
    nprobe: 8,
    max_candidates: None,
};
let config = SessionConfig::new()
    .with_target_partitions(2)
    .with_pq_vector();
let state = SessionStateBuilder::new()
    .with_default_features()
    .with_pq_vector(options)
    .with_config(config)
    .build();

Notes

  • k controls how many results you return.
  • nprobe trades speed for recall (higher = more accurate, slower).

License

MIT or Apache

Extension points exported contracts — how you extend this code

PqVectorSessionConfigExt (Interface)
Extensions for configuring `SessionConfig` to work with pq-vector. [1 implementers]
src/df_vector/session.rs
PqVectorSessionBuilderExt (Interface)
Extensions for configuring `SessionStateBuilder` to work with pq-vector. [1 implementers]
src/df_vector/session.rs

Core symbols most depended-on inside this repo

as_any
called by 47
src/df_vector/exec.rs
as_usize
called by 16
src/ivf/index.rs
as_str
called by 7
src/ivf/mod.rs
as_usize
called by 7
src/ivf/mod.rs
squared_l2_distance
called by 7
src/ivf/index.rs
children
called by 7
src/df_vector/exec.rs
dim
called by 6
src/ivf/mod.rs
dim
called by 5
src/ivf/index.rs

Shape

Method 84
Function 83
Class 31
Enum 3
Interface 2

Languages

Rust100%

Modules by API surface

src/ivf/parquet.rs32 symbols
src/df_vector/exec.rs32 symbols
src/ivf/index.rs23 symbols
benches/query.rs22 symbols
src/df_vector/index_exec.rs16 symbols
src/ivf/search.rs14 symbols
src/df_vector/physical.rs14 symbols
src/df_vector/access.rs14 symbols
src/ivf/mod.rs11 symbols
src/df_vector/tests.rs5 symbols
src/df_vector/expr.rs5 symbols
benches/bench_util.rs4 symbols

For agents

$ claude mcp add pq-vector \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact