Skip to main content

daimon_plugin_opensearch/
lib.rs

1//! # daimon-plugin-opensearch
2//!
3//! An OpenSearch k-NN backed [`VectorStore`](daimon_core::VectorStore) plugin
4//! for the [Daimon](https://docs.rs/daimon) AI agent framework.
5//!
6//! This crate provides [`OpenSearchVectorStore`], which stores document
7//! embeddings in [OpenSearch](https://opensearch.org/) using its native
8//! [k-NN plugin](https://opensearch.org/docs/latest/search-plugins/knn/index/).
9//! It supports cosine similarity, L2 (euclidean), and inner product distance
10//! metrics with HNSW indexing via nmslib, faiss, or lucene engines.
11//!
12//! ## Quick Start
13//!
14//! ```ignore
15//! use daimon_plugin_opensearch::{OpenSearchVectorStoreBuilder, SpaceType, Engine};
16//! use daimon::retriever::SimpleKnowledgeBase;
17//! use std::sync::Arc;
18//!
19//! let store = OpenSearchVectorStoreBuilder::new("http://localhost:9200", 1536)
20//!     .index("my_docs")
21//!     .space_type(SpaceType::CosineSimilarity)
22//!     .engine(Engine::Lucene)
23//!     .build()
24//!     .await?;
25//!
26//! // Compose with an embedding model for a full RAG pipeline:
27//! let kb = SimpleKnowledgeBase::new(embedding_model, store);
28//! ```
29//!
30//! ## Manual Index Setup
31//!
32//! If you prefer to manage index creation yourself, disable auto-creation
33//! and use the JSON from [`index_settings`]:
34//!
35//! ```ignore
36//! let store = OpenSearchVectorStoreBuilder::new(url, 1536)
37//!     .auto_create_index(false)
38//!     .build()
39//!     .await?;
40//! ```
41//!
42//! ## AWS OpenSearch Service
43//!
44//! Enable the `aws-auth` feature for SigV4 authentication:
45//!
46//! ```toml
47//! daimon-plugin-opensearch = { version = "0.15", features = ["aws-auth"] }
48//! ```
49
50mod builder;
51pub mod index_settings;
52mod store;
53
54pub use builder::OpenSearchVectorStoreBuilder;
55pub use store::OpenSearchVectorStore;
56
57/// Distance metric / space type for k-NN vector search.
58#[derive(Debug, Clone, Copy, PartialEq, Eq)]
59pub enum SpaceType {
60    /// Cosine similarity. Best for normalized embeddings.
61    CosineSimilarity,
62    /// Euclidean (L2) distance. Best for absolute spatial similarity.
63    L2,
64    /// Inner product. Best for maximum inner product search (MIPS).
65    InnerProduct,
66}
67
68impl SpaceType {
69    /// Returns the OpenSearch space type string used in index mappings.
70    pub fn as_str(&self) -> &'static str {
71        match self {
72            Self::CosineSimilarity => "cosinesimil",
73            Self::L2 => "l2",
74            Self::InnerProduct => "innerproduct",
75        }
76    }
77}
78
79impl Default for SpaceType {
80    fn default() -> Self {
81        Self::CosineSimilarity
82    }
83}
84
85/// k-NN engine used for approximate nearest neighbor search.
86#[derive(Debug, Clone, Copy, PartialEq, Eq)]
87pub enum Engine {
88    /// Apache Lucene engine. Good default, supports all space types.
89    Lucene,
90    /// NMSLIB engine. High performance for cosine and L2.
91    Nmslib,
92    /// FAISS engine. Supports IVF and HNSW, GPU-accelerated options.
93    Faiss,
94}
95
96impl Engine {
97    /// Returns the OpenSearch engine string used in index mappings.
98    pub fn as_str(&self) -> &'static str {
99        match self {
100            Self::Lucene => "lucene",
101            Self::Nmslib => "nmslib",
102            Self::Faiss => "faiss",
103        }
104    }
105}
106
107impl Default for Engine {
108    fn default() -> Self {
109        Self::Lucene
110    }
111}
112
113#[cfg(test)]
114mod tests {
115    use super::*;
116
117    #[test]
118    fn test_space_type_as_str() {
119        assert_eq!(SpaceType::CosineSimilarity.as_str(), "cosinesimil");
120        assert_eq!(SpaceType::L2.as_str(), "l2");
121        assert_eq!(SpaceType::InnerProduct.as_str(), "innerproduct");
122    }
123
124    #[test]
125    fn test_space_type_default() {
126        assert_eq!(SpaceType::default(), SpaceType::CosineSimilarity);
127    }
128
129    #[test]
130    fn test_engine_as_str() {
131        assert_eq!(Engine::Lucene.as_str(), "lucene");
132        assert_eq!(Engine::Nmslib.as_str(), "nmslib");
133        assert_eq!(Engine::Faiss.as_str(), "faiss");
134    }
135
136    #[test]
137    fn test_engine_default() {
138        assert_eq!(Engine::default(), Engine::Lucene);
139    }
140}