{"id":30523903,"url":"https://github.com/lightonai/fast-plaid","last_synced_at":"2025-10-10T11:05:01.843Z","repository":{"id":297197965,"uuid":"994618922","full_name":"lightonai/fast-plaid","owner":"lightonai","description":"High-Performance Engine for Multi-Vector Search","archived":false,"fork":false,"pushed_at":"2025-08-21T15:14:40.000Z","size":1948,"stargazers_count":146,"open_issues_count":2,"forks_count":8,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-08-21T16:54:24.590Z","etag":null,"topics":["colbert","colpali","information-retrieval","rust","vector-database"],"latest_commit_sha":null,"homepage":"https://github.com/lightonai/fast-plaid","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lightonai.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-06-02T08:10:32.000Z","updated_at":"2025-08-21T15:14:44.000Z","dependencies_parsed_at":"2025-06-04T16:38:22.725Z","dependency_job_id":"7d308712-bc56-4a48-9916-f24a78325b0b","html_url":"https://github.com/lightonai/fast-plaid","commit_stats":null,"previous_names":["lightonai/fast-plaid"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/lightonai/fast-plaid","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lightonai%2Ffast-plaid","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lightonai%2Ffast-plaid/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lightonai%2Ffast-plaid/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lightonai%2Ffast-plaid/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lightonai","download_url":"https://codeload.github.com/lightonai/fast-plaid/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lightonai%2Ffast-plaid/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272254492,"owners_count":24901054,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-26T02:00:07.904Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["colbert","colpali","information-retrieval","rust","vector-database"],"created_at":"2025-08-26T20:51:53.807Z","updated_at":"2025-10-10T11:05:01.835Z","avatar_url":"https://github.com/lightonai.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003ch1\u003eFastPlaid\u003c/h1\u003e\n\u003c/div\u003e\n\n\u003cp align=\"center\"\u003e\u003cimg width=500 src=\"https://github.com/lightonai/fast-plaid/blob/6184631dd9b9609efac8ce43e3e15be2efbb5355/docs/logo.png\"/\u003e\u003c/p\u003e\n\n\u003cdiv align=\"center\"\u003e\n    \u003ca href=\"https://github.com/rust-lang/rust\"\u003e\u003cimg src=\"https://img.shields.io/badge/rust-%23000000.svg?style=for-the-badge\u0026logo=rust\u0026logoColor=white\" alt=\"rust\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/pyo3\"\u003e\u003cimg src=\"https://img.shields.io/badge/PyO₃-%23000000.svg?style=for-the-badge\u0026logo=rust\u0026logoColor=white\" alt=\"PyO₃\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/LaurentMazare/tch-rs\"\u003e\u003cimg src=\"https://img.shields.io/badge/tch--rs-%23000000.svg?style=for-the-badge\u0026logo=rust\u0026logoColor=white\" alt=\"tch-rs\"\u003e\u003c/a\u003e\n\u003c/div\u003e\n\n\u0026nbsp;\n\n\u003cdiv align=\"center\"\u003e\n    \u003cb\u003eFastPlaid\u003c/b\u003e - A High-Performance Engine for Multi-Vector Search\n\u003c/div\u003e\n\n\u0026nbsp;\n\n## ⭐️ Overview\n\nTraditional vector search relies on single, fixed-size embeddings (dense vectors) for documents and queries. While powerful, this approach can lose nuanced, token-level details.\n\n- **Multi-vector search**, used in models like [ColBERT](https://github.com/lightonai/pylate) or [ColPali](https://github.com/illuin-tech/colpali), replaces a single document or image vector with a set of per-token vectors. This enables a \"late interaction\" mechanism, where fine-grained similarity is calculated term-by-term to boost retrieval accuracy.\n\n- **Higher Accuracy:** By matching at a granular, token-level, FastPlaid captures subtle relevance that single-vector models simply miss.\n\n- **PLAID:** stands for _Per-Token Late Interaction Dense Search_.\n\n- **Blazing Performance**: Engineered in Rust and optimized for **GPUs**.\n\n\u0026nbsp;\n\n## 💻 Installation\n\n```bash\npip install fast-plaid\n```\n\n## PyTorch Compatibility\n\nFastPlaid is available in multiple versions to support different PyTorch versions:\n\n| FastPlaid Version | PyTorch Version | Installation Command                |\n| ----------------- | --------------- | ----------------------------------- |\n| 1.2.4.280         | 2.8.0           | `pip install fast-plaid==1.2.4.280` |\n| 1.2.4.271         | 2.7.1           | `pip install fast-plaid==1.2.4.271` |\n| 1.2.4.270         | 2.7.0           | `pip install fast-plaid==1.2.4.270` |\n| 1.2.4.260         | 2.6.0           | `pip install fast-plaid==1.2.4.260` |\n\n### Adding FastPlaid as a Dependency\n\nYou can add FastPlaid to your project dependencies with version ranges to ensure compatibility:\n\n**For requirements.txt:**\n\n```\nfast-plaid\u003e=1.2.4.260,\u003c=1.2.4.280\n```\n\n**For pyproject.toml:**\n\n```toml\n[project]\ndependencies = [\n    \"fast-plaid\u003e=1.2.4.260,\u003c=1.2.4.280\"\n]\n```\n\n**For setup.py:**\n\n```python\ninstall_requires=[\n    \"fast-plaid\u003e=1.2.4.260,\u003c=1.2.4.280\"\n]\n```\n\nChoose the appropriate version range based on your PyTorch requirements.\n\n**Building from Source:**\n\n```python\ncurl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh\npip install git+https://github.com/lightonai/fast-plaid.git\n```\n\n\u0026nbsp;\n\n## ⚡️ Quick Start\n\nGet started with creating an index and performing a search in just a few lines of Python.\n\n```python\nimport torch\n\nfrom fast_plaid import search\n\nfast_plaid = search.FastPlaid(index=\"index\")\n\nembedding_dim = 128\n\n# Index 100 documents, each with 300 tokens, each token is a 128-dim vector.\nfast_plaid.create(\n    documents_embeddings=[torch.randn(300, embedding_dim) for _ in range(100)]\n)\n\n# Search for 2 queries, each with 50 tokens, each token is a 128-dim vector\nscores = fast_plaid.search(\n    queries_embeddings=torch.randn(2, 50, embedding_dim),\n    top_k=10,\n)\n\nprint(scores)\n```\n\nThe output will be a list of lists, where each inner list contains tuples of (document_index, similarity_score) for the top top_k results for each query:\n\n```python\n[\n    [\n        (20, 1334.55),\n        (91, 1299.57),\n        (59, 1285.78),\n        (10, 1273.53),\n        (62, 1267.96),\n        (44, 1265.55),\n        (15, 1264.42),\n        (34, 1261.19),\n        (19, 1261.05),\n        (86, 1260.94),\n    ],\n    [\n        (58, 1313.85),\n        (75, 1313.82),\n        (79, 1305.32),\n        (61, 1304.45),\n        (64, 1303.67),\n        (68, 1302.98),\n        (66, 1301.23),\n        (65, 1299.78),\n    ],\n]\n```\n\n## 🗂️ Update an Index\n\n```python\nimport torch\n\nfrom fast_plaid import search\n\nfast_plaid = search.FastPlaid(index=\"index\") # Load an existing index\n\nembedding_dim = 128\n\nfast_plaid.update(\n    documents_embeddings=[torch.randn(300, embedding_dim) for _ in range(100)]\n)\n\nscores = fast_plaid.search(\n    queries_embeddings=torch.randn(2, 50, embedding_dim),\n    top_k=10,\n)\n\nprint(scores)\n```\n\nIt is highly recommended to create your initial index with a large and representative sample of your data for optimal performance and accuracy. The **`.create()` method** establishes the fundamental structure of the index by calculating centroids that are specifically tailored to the distribution of this initial dataset.\n\nThe **`.update()` method**, designed for efficiency, **does not re-compute these centroids**. Instead, it places new documents into the existing structure. If you frequently update the index with large volumes of data that have a different statistical distribution than the original set, you may experience \"drift.\" This means the fixed centroids become less representative of the total collection, potentially leading to sub-optimal data partitioning and a gradual decline in retrieval accuracy over time. Therefore, building a robust initial index is key to its long-term health. If you find that your data distribution changes significantly, consider periodically re-creating the index with a new, representative sample to maintain optimal performance or avoid using the `.update()` method and rely on the **`.create()` method** which will delete the existing index and re-create it from scratch. To update an existing embedding, you should delete it first and then add the new version with the `.update()` method.\n\n\u0026nbsp;\n\n## 🔎 Filtering\n\nYou can restrict your search to a specific subset of documents by using the `subset` parameter in the `.search()` method. This is useful for implementing metadata filtering or searching within a pre-defined collection.\n\nThe `subset` parameter accepts a list of IDs. These IDs correspond directly to the order of insertion, starting from 0. For example, if you index 100 documents with `.create()`, they will have IDs `0` through `99`. If you then add `50` more documents with `.update()`, they will be assigned the subsequent IDs `100` through `149`.\n\nYou can provide a single list of IDs to apply the same filter to all queries, or a list of lists to specify a different filter for each query.\n\n```python\nimport torch\nfrom fast_plaid import search\n\n\nfast_plaid = search.FastPlaid(index=\"index\") # Load an existing index\n\n# Apply a single filter to all queries\n# Search for the top 5 results only within documents [2, 5, 10, 15, 18]\nscores = fast_plaid.search(\n    queries_embeddings=torch.randn(2, 50, 128), # 2 queries\n    top_k=5,\n    subset=[2, 5, 10, 15, 18]\n)\n\nprint(scores)\n\n# Apply a different filter for each query\n# Query 1: search within documents [0, 1, 2, 3, 4]\n# Query 2: search within documents [10, 11, 12, 13, 14]\nscores = fast_plaid.search(\n    queries_embeddings=torch.randn(2, 50, 128), # 2 queries\n    top_k=5,\n    subset=[\n        [0, 1, 2, 3, 4],\n        [10, 11, 12, 13, 14]\n    ]\n)\n\nprint(scores)\n```\n\nProviding a `subset` filter can significantly speed up the search process, especially when the subset is much smaller than the total number of indexed documents.\n\n\u0026nbsp;\n\n## 📊 Benchmarks\n\nFastPlaid significantly outperforms the original PLAID engine across various datasets, delivering comparable accuracy with faster indexing and query speeds.\n\n```python\n                                   NDCG@10  Indexing Time (s) Queries per seconds (QPS)\ndataset          size   library\narguana          8674   PLAID         0.46               4.30                     56.73\n                        FastPlaid     0.46               4.72            155.25 (+174%)\n\nfiqa             57638  PLAID         0.41              17.65                     48.13\n                        FastPlaid     0.41              12.62            146.62 (+205%)\n\nnfcorpus         3633   PLAID         0.37               2.30                     78.31\n                        FastPlaid     0.37               2.10            243.42 (+211%)\n\nquora            522931 PLAID         0.88              40.01                     43.06\n                        FastPlaid     0.87              11.23            281.51 (+554%)\n\nscidocs          25657  PLAID         0.19              13.32                     57.17\n                        FastPlaid     0.18              10.86            157.47 (+175%)\n\nscifact          5183   PLAID         0.74               3.43                     67.66\n                        FastPlaid     0.75               3.16            190.08 (+181%)\n\ntrec-covid       171332 PLAID         0.84              69.46                     32.09\n                        FastPlaid     0.83              45.19              54.11 (+69%)\n\nwebis-touche2020 382545 PLAID         0.25             128.11                     31.94\n                        FastPlaid     0.24              74.50             70.15 (+120%)\n```\n\n_All benchmarks were performed on an H100 GPU. It's important to note that PLAID relies on Just-In-Time (JIT) compilation. This means the very first execution can exhibit longer runtimes. To ensure our performance analysis is representative, we've excluded these initial JIT-affected runs from the reported results. In contrast, FastPlaid does not employ JIT compilation, so its performance on the first run is directly indicative of its typical execution speed._\n\n\u0026nbsp;\n\n## ⚖️ Settings Trade-offs\n\n### Indexing\n\n```python\nParameter         Default     Speed                        Accuracy                     Description\nn_samples_kmeans  None        lower = faster               lower = less precise         Number of samples to compute centroids\nnbits             4           lower  = faster              lower  = less precise        product quantization bits\nkmeans_niters     4           higher = slower indexing     higher = better clusters     K-means iterations\n```\n\n### Search\n\n```python\nParameter         Default     Speed               Accuracy                    Description\nn_ivf_probe       8           higher = slower     higher = better recall      cluster probes per query\nn_full_scores     4096        higher = slower     higher = better ranking     candidates for full scoring\n```\n\n\u0026nbsp;\n\n## 📝 Citation\n\nFastPlaid builds upon the groundbreaking work of the original PLAID engine [Santhanam, Keshav, et al.](https://arxiv.org/abs/2205.09707).\n\nYou can cite **FastPlaid** in your work as follows:\n\n```bibtex\n@misc{fastplaid2025,\n  author = {Sourty, Raphaël},\n  title = {FastPlaid: A High-Performance Engine for Multi-Vector Search},\n  year = {2025},\n  url = {https://github.com/lightonai/fast-plaid}\n}\n```\n\nAnd for the original PLAID research:\n\n```bibtex\n@inproceedings{santhanam2022plaid,\n  title={{PLAID}: an efficient engine for late interaction retrieval},\n  author={Santhanam, Keshav and Khattab, Omar and Potts, Christopher and Zaharia, Matei},\n  booktitle={Proceedings of the 31st ACM International Conference on Information \\\u0026 Knowledge Management},\n  pages={1747--1756},\n  year={2022}\n}\n```\n\n\u0026nbsp;\n\n## 📖 FastPlaid Class\n\nThe **`FastPlaid` class** is the core component for building and querying multi-vector search indexes. It's designed for **high performance**, especially when leveraging GPUs.\n\n### Initialization\n\nTo create an instance of `FastPlaid`, you'll provide the directory where your index will be stored and specify the device(s) for computation.\n\n```python\nclass FastPlaid:\n    def __init__(\n        self,\n        index: str,\n        device: str | list[str] | None = None,\n    ) -\u003e None:\n```\n\n```\nindex: str\n    The file path to the directory where your index will be saved or loaded from.\n\ndevice: str | list[str] | None = None\n    Specifies the device(s) to use for computation.\n    - If None (default) and CUDA is available, it defaults to \"cuda\".\n    - If CUDA is not available, it defaults to \"cpu\".\n    - Can be a single device string (e.g., \"cuda:0\" or \"cpu\").\n    - Can be a list of device strings (e.g., [\"cuda:0\", \"cuda:1\"]).\n    - If multiple GPUs are specified and available, multiprocessing is automatically set up for parallel execution.\n      Remember to include your code within an `if __name__ == \"__main__\":` block for proper multiprocessing behavior.\n```\n\n### Creating an Index\n\nThe **`create` method** builds the multi-vector index from your document embeddings. It uses K-means clustering to organize your data for efficient retrieval.\n\n```python\n    def create(\n        self,\n        documents_embeddings: list[torch.Tensor] | torch.Tensor,\n        kmeans_niters: int = 4,\n        max_points_per_centroid: int = 256,\n        nbits: int = 4,\n        n_samples_kmeans: int | None = None,\n        seed: int = 42,\n        use_triton_kmeans: bool | None = None,\n        metadata: list[dict[str, Any]] | None = None,\n    ) -\u003e \"FastPlaid\":\n```\n\n```\ndocuments_embeddings: list[torch.Tensor] | torch.Tensor\n    A list where each element is a PyTorch tensor representing the multi-vector embedding for a single document.\n    Each document's embedding should have a shape of `(num_tokens, embedding_dimension)`. Can also be a single tensor of shape `(num_documents, num_tokens, embedding_dimension)`.\n\nkmeans_niters: int = 4 (optional)\n    The number of iterations for the K-means algorithm used during index creation.\n    This influences the quality of the initial centroid assignments.\n\nmax_points_per_centroid: int = 256 (optional)\n    The maximum number of points (token embeddings) that can be assigned to a single centroid during K-means.\n    This helps in balancing the clusters.\n\nnbits: int = 4 (optional)\n    The number of bits to use for product quantization.\n    This parameter controls the compression of your embeddings, impacting both index size and search speed.\n    Lower values mean more compression and potentially faster searches but can reduce accuracy.\n\nn_samples_kmeans: int | None = None (optional)\n    The number of samples to use for K-means clustering.\n    If `None`, it defaults to a value based on the number of documents.\n    This parameter can be adjusted to balance between speed, memory usage and\n    clustering quality. If you have a large dataset, you might want to set this to a\n    smaller value to speed up the indexing process and save some memory.\n\nseed: int = 42 (optional)\n    Seed for the random number generator used in index creation.\n    Setting this ensures reproducible results across multiple runs.\n\nuse_triton_kmeans: bool | None = None (optional)\n    Whether to use the Triton-based K-means implementation.\n    If `None`, it will be set to True if the device is not \"cpu\".\n    Triton-based implementation can provide better performance on GPUs.\n    Set to False to ensure perfectly reproducible results across runs.\n\nmetadata: list[dict[str, Any]] | None = None (optional)\n    An optional list of metadata dictionaries corresponding to each document being indexed.\n    Each dictionary can contain arbitrary key-value pairs that you want to associate with the document.\n    If provided, the length of this list must match the number of documents being indexed.\n    The metadata will be stored in a SQLite database within the index directory for filtering during searches.\n```\n\n### Updating the Index\n\nThe **`update` method** provides an efficient way to add new documents to an existing index without rebuilding it from scratch. This is significantly faster than calling .create() again, as it reuses the existing quantization configuration and only processes the new documents. The centroids and quantization parameters remain unchanged, **this might lead to a slight decrease in accuracy compared to a full re-indexing**. To update an existing embedding, you should delete it first and then add the new version with the `.update()` method.\n\n```python\n    def update(\n        self,\n        documents_embeddings: list[torch.Tensor] | torch.Tensor,\n        metadata: list[dict[str, Any]] | None = None,\n    ) -\u003e \"FastPlaid\":\n```\n\n```\ndocuments_embeddings: list[torch.Tensor]\n    A list where each element is a PyTorch tensor representing the multi-vector embedding for a single document.\n    Each document's embedding should have a shape of `(num_tokens, embedding_dimension)`.\n    This method will add these new embeddings to the existing index.\n\nmetadata: list[dict[str, Any]] | None = None\n    An optional list of metadata dictionaries corresponding to each new document being added.\n    Each dictionary can contain arbitrary key-value pairs that you want to associate with the document.\n    If provided, the length of this list must match the number of new documents being added.\n    The metadata will be stored in a SQLite database within the index directory for filtering during searches.\n```\n\n### Searching the Index\n\nThe **`search` method** lets you query the created index with your query embeddings and retrieve the most relevant documents.\n\n```python\n    def search(\n        self,\n        queries_embeddings: torch.Tensor | list[torch.Tensor],\n        top_k: int = 10,\n        batch_size: int = 1 \u003c\u003c 18,\n        n_full_scores: int = 4096,\n        n_ivf_probe: int = 8,\n        show_progress: bool = True,\n        subset: list[list[int]] | list[int] | None = None,\n    ) -\u003e list[list[tuple[int, float]]]:\n```\n\n```\nqueries_embeddings: torch.Tensor | list[torch.Tensor]\n    A PyTorch tensor representing the multi-vector embeddings of your queries.\n    Its shape should be `(num_queries, num_tokens_per_query, embedding_dimension)`.\n    Can also be a list of tensors, each representing a separate query. All tensors in the list must have the same embedding dimension.\n\ntop_k: int = 10 (optional)\n    The number of top-scoring documents to retrieve for each query.\n\nbatch_size: int = 1 \u003c\u003c 18 (optional)\n    The internal batch size used for processing queries.\n    A larger batch size might improve throughput on powerful GPUs but can consume more memory.\n\nn_full_scores: int = 4096 (optional)\n    The number of candidate documents for which full (re-ranked) scores are computed.\n    This is a crucial parameter for accuracy; higher values lead to more accurate results but increase computation.\n\nn_ivf_probe: int = 8 (optional)\n    The number of inverted file list \"probes\" to perform during the search.\n    This parameter controls the number of clusters to search within the index for each query.\n    Higher values improve recall but increase search time.\n\nshow_progress: bool = True (optional)\n    If set to `True`, a progress bar will be displayed during the search operation.\n\nsubset: list[list[int]] | list[int] | None = None (optional)\n    An optional list of lists of integers or a single list of integers. If provided, the search\n    for each query will be restricted to the document IDs in the corresponding inner list.\n    - If a single list is provided, the same filter will be applied to all queries.\n    - If a list of lists is provided, each inner list corresponds to the filter for each query.\n    - Document IDs correspond to the order of insertion, starting from 0.\n```\n\n### Deleting from the Index\n\nThe **`delete` method** allows to permanently remove embeddings from the index based on their insertion order IDs. If a metadata database exists, the corresponding entries will also be automatically removed. To update an existing embedding, you should delete it first and then add the new version with the `.update()` method.\n\n```python\n    def delete(\n        self,\n        subset: list[int],\n    ) -\u003e \"FastPlaid\":\n```\n\n```\nsubset: list[int]\n    A list of embeddings IDs to delete from the index. The IDs are based on the original\n    order of insertion, starting from 0. After deletion, the remaining documents are\n    re-indexed to maintain a sequential order.\n```\n\n## Contributing\n\nAny contributions to FastPlaid are welcome! If you have ideas for improvements, bug fixes, or new features, please open an issue or submit a pull request. We are particularly interested in:\n\n- Re-computing centroids when using the `.update()` method to maintain optimal performance.\n- Additional algorithms for multi-vector search.\n- New search outputs formats for better integration with existing systems.\n\n\u0026nbsp;\n\n## 🗂️ Built-in SQLite Filtering\n\nFastPlaid includes a lightweight, optional, built-in metadata filtering engine powered by SQLite. When you provide the metadata parameter during .create() or .update(), FastPlaid automatically stores this information in a searchable database within your index directory.\n\nYou can then use the fast_plaid.filtering.where() function to query this database using standard SQL conditions. This function returns a list of embeddings IDs that match your criteria, which you can pass directly to the subset parameter of the .search() method to pre-filter your search.\n\n```python\nfrom datetime import date\n\nimport torch\nfrom fast_plaid import filtering, search\n\n# 1. Initialize the FastPlaid index\nfast_plaid = search.FastPlaid(index=\"metadata_index\")\nembedding_dim = 128\n\n# 2. Create initial documents with metadata\ninitial_embeddings = [torch.randn(10, embedding_dim) for _ in range(3)]\ninitial_metadata = [\n    {\"name\": \"Alice\", \"category\": \"A\", \"join_date\": date(2023, 5, 17)},\n    {\"name\": \"Bob\", \"category\": \"B\", \"join_date\": date(2021, 6, 21)},\n    {\"name\": \"Alex\", \"category\": \"A\", \"join_date\": date(2023, 8, 1)},\n]\n\nfast_plaid.create(documents_embeddings=initial_embeddings, metadata=initial_metadata)\n\n# 3. Update the index with new documents and metadata\nnew_embeddings = [torch.randn(10, embedding_dim) for _ in range(2)]\nnew_metadata = [\n    {\"name\": \"Charlie\", \"category\": \"B\", \"join_date\": date(2020, 3, 15)},\n    {\n        \"name\": \"Amanda\",\n        \"category\": \"A\",\n        \"join_date\": date(2024, 1, 10),\n        \"status\": \"active\",\n    },\n]\n\nfast_plaid.update(documents_embeddings=new_embeddings, metadata=new_metadata)\n\n# 4. Use filtering.where to get the corresponding rows of the FastPlaid index\n# which match the SQL condition\nsubset = filtering.where(\n    index=\"metadata_index\",\n    condition=\"name LIKE ? AND join_date \u003e ?\",\n    parameters=(\"A%\", \"2022-12-31\"),\n)\n\n# 5. Perform a search restricted to the filtered subset\nquery_embedding = torch.randn(1, 5, embedding_dim)\nscores = fast_plaid.search(queries_embeddings=query_embedding, top_k=3, subset=subset)\n\nprint(\"Search results within the subset:\")\nprint(scores)\n\n# 5. Access to the metadata of the retrieved documents\nfor match in scores:\n    print(\"Metadata of matched documents:\")\n    print(filtering.get(index=\"metadata_index\", subset=[subset for subset, _ in match]))\n```\n\nYou can also rely on the existing subset parameter of the .search() method to filter candidates based\non the order of insertion or rely on an external filtering system as providing the metadata parameter is optional.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flightonai%2Ffast-plaid","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flightonai%2Ffast-plaid","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flightonai%2Ffast-plaid/lists"}