Skip to content

Commit f6a648e

Browse files
aseovicmarkpollack
authored andcommitted
Add Oracle Coherence vector store implementation
Integrates Oracle Coherence 24.09+ as a vector store backend for Spring AI. The implementation provides: - Support for vector similarity search with configurable distance metrics (Cosine, Inner Product, L2) - Multiple indexing options including HNSW and Binary Quantization indexes - Filter expression evaluation for metadata-based filtering - Vector normalization capabilities - Comprehensive test coverage including integration tests The implementation includes: - CoherenceVectorStore main implementation - CoherenceFilterExpressionConverter for Spring AI to Coherence filter conversion - Auto-configuration support via spring-boot-starter - Documentation and usage examples Requires Oracle Coherence 24.09 or later.
1 parent 99d9864 commit f6a648e

File tree

8 files changed

+935
-6
lines changed

8 files changed

+935
-6
lines changed

pom.xml

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,38 +47,43 @@
4747
<module>vector-stores/spring-ai-azure-store</module>
4848
<module>vector-stores/spring-ai-cassandra-store</module>
4949
<module>vector-stores/spring-ai-chroma-store</module>
50+
<module>vector-stores/spring-ai-coherence-store</module>
5051
<module>vector-stores/spring-ai-elasticsearch-store</module>
51-
5252
<module>vector-stores/spring-ai-gemfire-store</module>
5353
<module>vector-stores/spring-ai-hanadb-store</module>
5454
<module>vector-stores/spring-ai-milvus-store</module>
5555
<module>vector-stores/spring-ai-mongodb-atlas-store</module>
5656
<module>vector-stores/spring-ai-neo4j-store</module>
57+
<module>vector-stores/spring-ai-opensearch-store</module>
5758
<module>vector-stores/spring-ai-oracle-store</module>
5859
<module>vector-stores/spring-ai-pgvector-store</module>
5960
<module>vector-stores/spring-ai-pinecone-store</module>
6061
<module>vector-stores/spring-ai-qdrant-store</module>
6162
<module>vector-stores/spring-ai-redis-store</module>
6263
<module>vector-stores/spring-ai-typesense-store</module>
63-
6464
<module>vector-stores/spring-ai-weaviate-store</module>
65+
66+
<module>spring-ai-spring-boot-starters/spring-ai-starter-aws-opensearch-store</module>
6567
<module>spring-ai-spring-boot-starters/spring-ai-starter-azure-cosmos-db-store</module>
6668
<module>spring-ai-spring-boot-starters/spring-ai-starter-azure-store</module>
6769
<module>spring-ai-spring-boot-starters/spring-ai-starter-cassandra-store</module>
6870
<module>spring-ai-spring-boot-starters/spring-ai-starter-chroma-store</module>
71+
<module>spring-ai-spring-boot-starters/spring-ai-starter-coherence-store</module>
6972
<module>spring-ai-spring-boot-starters/spring-ai-starter-elasticsearch-store</module>
7073
<module>spring-ai-spring-boot-starters/spring-ai-starter-gemfire-store</module>
7174
<module>spring-ai-spring-boot-starters/spring-ai-starter-hanadb-store</module>
7275
<module>spring-ai-spring-boot-starters/spring-ai-starter-milvus-store</module>
7376
<module>spring-ai-spring-boot-starters/spring-ai-starter-mongodb-atlas-store</module>
7477
<module>spring-ai-spring-boot-starters/spring-ai-starter-neo4j-store</module>
78+
<module>spring-ai-spring-boot-starters/spring-ai-starter-opensearch-store</module>
7579
<module>spring-ai-spring-boot-starters/spring-ai-starter-oracle-store</module>
7680
<module>spring-ai-spring-boot-starters/spring-ai-starter-pgvector-store</module>
7781
<module>spring-ai-spring-boot-starters/spring-ai-starter-pinecone-store</module>
7882
<module>spring-ai-spring-boot-starters/spring-ai-starter-qdrant-store</module>
7983
<module>spring-ai-spring-boot-starters/spring-ai-starter-redis-store</module>
8084
<module>spring-ai-spring-boot-starters/spring-ai-starter-typesense-store</module>
8185
<module>spring-ai-spring-boot-starters/spring-ai-starter-weaviate-store</module>
86+
8287
<module>models/spring-ai-anthropic</module>
8388
<module>models/spring-ai-azure-openai</module>
8489
<module>models/spring-ai-bedrock</module>
@@ -93,13 +98,13 @@
9398
<module>models/spring-ai-qianfan</module>
9499
<module>models/spring-ai-stability-ai</module>
95100
<module>models/spring-ai-transformers</module>
96-
<module>models/spring-ai-vertex-ai-gemini</module>
97101
<module>models/spring-ai-vertex-ai-embedding</module>
102+
<module>models/spring-ai-vertex-ai-gemini</module>
98103
<module>models/spring-ai-watsonx-ai</module>
99104
<module>models/spring-ai-zhipuai</module>
100105
<module>models/spring-ai-moonshot</module>
106+
101107
<module>spring-ai-spring-boot-starters/spring-ai-starter-anthropic</module>
102-
<module>spring-ai-spring-boot-starters/spring-ai-starter-aws-opensearch-store</module>
103108
<module>spring-ai-spring-boot-starters/spring-ai-starter-azure-openai</module>
104109
<module>spring-ai-spring-boot-starters/spring-ai-starter-bedrock-ai</module>
105110
<module>spring-ai-spring-boot-starters/spring-ai-starter-bedrock-converse</module>
@@ -118,8 +123,6 @@
118123
<module>spring-ai-spring-boot-starters/spring-ai-starter-watsonx-ai</module>
119124
<module>spring-ai-spring-boot-starters/spring-ai-starter-zhipuai</module>
120125
<module>spring-ai-spring-boot-starters/spring-ai-starter-moonshot</module>
121-
<module>vector-stores/spring-ai-opensearch-store</module>
122-
<module>spring-ai-spring-boot-starters/spring-ai-starter-opensearch-store</module>
123126
</modules>
124127

125128
<organization>
@@ -197,6 +200,7 @@
197200
<pdfbox.version>3.0.3</pdfbox.version>
198201
<pgvector.version>0.1.6</pgvector.version>
199202
<sap.hanadb.version>2.20.11</sap.hanadb.version>
203+
<coherence.version>24.09</coherence.version>
200204
<oracle.version>23.4.0.24.05</oracle.version>
201205
<postgresql.version>42.7.2</postgresql.version>
202206
<elasticsearch-java.version>8.13.3</elasticsearch-java.version>
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
~ Copyright 2023-2024 the original author or authors.
4+
~
5+
~ Licensed under the Apache License, Version 2.0 (the "License");
6+
~ you may not use this file except in compliance with the License.
7+
~ You may obtain a copy of the License at
8+
~
9+
~ https://www.apache.org/licenses/LICENSE-2.0
10+
~
11+
~ Unless required by applicable law or agreed to in writing, software
12+
~ distributed under the License is distributed on an "AS IS" BASIS,
13+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
~ See the License for the specific language governing permissions and
15+
~ limitations under the License.
16+
-->
17+
18+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
19+
<modelVersion>4.0.0</modelVersion>
20+
<parent>
21+
<groupId>org.springframework.ai</groupId>
22+
<artifactId>spring-ai</artifactId>
23+
<version>1.0.0-SNAPSHOT</version>
24+
<relativePath>../../pom.xml</relativePath>
25+
</parent>
26+
<artifactId>spring-ai-coherence-store-spring-boot-starter</artifactId>
27+
<packaging>jar</packaging>
28+
<name>Spring AI Starter - Coherence Vector Store</name>
29+
<description>Spring AI Coherence Vector Store Auto Configuration</description>
30+
<url>https://github.com/spring-projects/spring-ai</url>
31+
32+
<scm>
33+
<url>https://github.com/spring-projects/spring-ai</url>
34+
<connection>git://github.com/spring-projects/spring-ai.git</connection>
35+
<developerConnection>[email protected]:spring-projects/spring-ai.git</developerConnection>
36+
</scm>
37+
38+
<dependencies>
39+
40+
<dependency>
41+
<groupId>org.springframework.boot</groupId>
42+
<artifactId>spring-boot-starter</artifactId>
43+
</dependency>
44+
45+
<dependency>
46+
<groupId>org.springframework.ai</groupId>
47+
<artifactId>spring-ai-spring-boot-autoconfigure</artifactId>
48+
<version>${project.parent.version}</version>
49+
</dependency>
50+
51+
<dependency>
52+
<groupId>org.springframework.ai</groupId>
53+
<artifactId>spring-ai-coherence-store</artifactId>
54+
<version>${project.parent.version}</version>
55+
</dependency>
56+
</dependencies>
57+
58+
</project>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[Oracle Coherence Vector Search Documentation](https://docs.oracle.com/)
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
<parent>
7+
<groupId>org.springframework.ai</groupId>
8+
<artifactId>spring-ai</artifactId>
9+
<version>1.0.0-SNAPSHOT</version>
10+
<relativePath>../../pom.xml</relativePath>
11+
</parent>
12+
<artifactId>spring-ai-coherence-store</artifactId>
13+
<packaging>jar</packaging>
14+
<name>Spring AI Vector Store - Coherence</name>
15+
<description>AI Vector Search from Oracle Coherence 24.09+ as a Spring AI Vector Store</description>
16+
<url>https://github.com/spring-projects/spring-ai</url>
17+
18+
<scm>
19+
<url>https://github.com/spring-projects/spring-ai</url>
20+
<connection>git://github.com/spring-projects/spring-ai.git</connection>
21+
<developerConnection>[email protected]:spring-projects/spring-ai.git</developerConnection>
22+
</scm>
23+
24+
<properties>
25+
<coherence.groupId>com.oracle.coherence.ce</coherence.groupId>
26+
</properties>
27+
28+
<dependencies>
29+
<dependency>
30+
<groupId>org.springframework.ai</groupId>
31+
<artifactId>spring-ai-core</artifactId>
32+
<version>${parent.version}</version>
33+
</dependency>
34+
35+
<dependency>
36+
<groupId>org.slf4j</groupId>
37+
<artifactId>slf4j-api</artifactId>
38+
<version>2.0.13</version>
39+
</dependency>
40+
41+
<dependency>
42+
<groupId>${coherence.groupId}</groupId>
43+
<artifactId>coherence</artifactId>
44+
<version>${coherence.version}</version>
45+
<scope>provided</scope>
46+
</dependency>
47+
<dependency>
48+
<groupId>${coherence.groupId}</groupId>
49+
<artifactId>coherence-hnsw</artifactId>
50+
<version>${coherence.version}</version>
51+
</dependency>
52+
53+
<!-- TESTING -->
54+
<dependency>
55+
<groupId>org.springframework.ai</groupId>
56+
<artifactId>spring-ai-transformers</artifactId>
57+
<version>${parent.version}</version>
58+
<scope>test</scope>
59+
</dependency>
60+
61+
62+
<dependency>
63+
<groupId>org.springframework.ai</groupId>
64+
<artifactId>spring-ai-test</artifactId>
65+
<version>${parent.version}</version>
66+
<scope>test</scope>
67+
</dependency>
68+
69+
<dependency>
70+
<groupId>org.springframework.boot</groupId>
71+
<artifactId>spring-boot-starter-test</artifactId>
72+
<scope>test</scope>
73+
</dependency>
74+
75+
<dependency>
76+
<groupId>${coherence.groupId}</groupId>
77+
<artifactId>coherence-bedrock-testing-support</artifactId>
78+
<version>${coherence.version}</version>
79+
<scope>test</scope>
80+
</dependency>
81+
</dependencies>
82+
83+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Copyright 2023-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.ai.vectorstore;
18+
19+
import java.util.List;
20+
21+
import com.tangosol.util.Filter;
22+
import com.tangosol.util.Filters;
23+
import com.tangosol.util.ValueExtractor;
24+
import com.tangosol.util.extractor.ChainedExtractor;
25+
import com.tangosol.util.extractor.UniversalExtractor;
26+
27+
import org.springframework.ai.vectorstore.filter.Filter.Expression;
28+
import org.springframework.ai.vectorstore.filter.Filter.Group;
29+
import org.springframework.ai.vectorstore.filter.Filter.Key;
30+
import org.springframework.ai.vectorstore.filter.Filter.Operand;
31+
import org.springframework.ai.vectorstore.filter.Filter.Value;
32+
import org.springframework.ai.vectorstore.filter.FilterHelper;
33+
34+
/**
35+
* Converts Spring AI {@link Expression} into Coherence {@link Filter}.
36+
*
37+
* @author Aleks Seovic
38+
*/
39+
@SuppressWarnings({ "rawtypes", "unchecked" })
40+
public class CoherenceFilterExpressionConverter {
41+
42+
public Filter<?> convert(Operand expression) {
43+
if (expression instanceof Expression) {
44+
return convert((Expression) expression);
45+
}
46+
return convert((Group) expression);
47+
}
48+
49+
private Filter<?> convert(Group group) {
50+
return convert(group.content());
51+
}
52+
53+
private Filter<?> convert(Expression expression) {
54+
return switch (expression.type()) {
55+
case EQ -> Filters.equal(extractor(expression.left()), value(expression.right()));
56+
case NE -> Filters.notEqual(extractor(expression.left()), value(expression.right()));
57+
case GT -> Filters.greater(extractor(expression.left()), value(expression.right()));
58+
case GTE -> Filters.greaterEqual(extractor(expression.left()), value(expression.right()));
59+
case LT -> Filters.less(extractor(expression.left()), value(expression.right()));
60+
case LTE -> Filters.lessEqual(extractor(expression.left()), value(expression.right()));
61+
case IN -> Filters.in(extractor(expression.left()), ((List) value(expression.right())).toArray());
62+
case NIN ->
63+
Filters.not(Filters.in(extractor(expression.left()), ((List) value(expression.right())).toArray()));
64+
case NOT -> convert(FilterHelper.negate(expression));
65+
case AND -> and(expression);
66+
case OR -> or(expression);
67+
};
68+
}
69+
70+
private Filter<?> and(Expression expression) {
71+
Filter<?> left = convert(expression.left());
72+
Filter<?> right = convert(expression.right());
73+
return left.and(right);
74+
}
75+
76+
private Filter<?> or(Expression expression) {
77+
Filter<?> left = convert(expression.left());
78+
Filter<?> right = convert(expression.right());
79+
return left.or(right);
80+
}
81+
82+
private ValueExtractor extractor(Operand op) {
83+
return new ChainedExtractor(new UniversalExtractor<>("metadata"), new UniversalExtractor<>(((Key) op).key()));
84+
}
85+
86+
private <T> T value(Operand op) {
87+
return (T) ((Value) op).value();
88+
}
89+
90+
}

0 commit comments

Comments
 (0)