Add OpenSearch Service Connection support
Service Connection support for Docker Compose and Testcontainers.
This commit is contained in:
committed by
Christian Tzolov
parent
5844f9bf39
commit
37c222a5f3
@@ -37,6 +37,9 @@ The following service connection factories are provided in the `spring-ai-spring
|
||||
| `OllamaConnectionDetails`
|
||||
| Containers named `ollama/ollama`
|
||||
|
||||
| `OpenSearchConnectionDetails`
|
||||
| Containers named `opensearchproject/opensearch`
|
||||
|
||||
| `QdrantConnectionDetails`
|
||||
| Containers named `qdrant/qdrant`
|
||||
|
||||
|
||||
@@ -40,6 +40,9 @@ The following service connection factories are provided in the `spring-ai-spring
|
||||
| `OllamaConnectionDetails`
|
||||
| Containers of type `OllamaContainer`
|
||||
|
||||
| `OpenSearchConnectionDetails`
|
||||
| Containers of type `OpensearchContainer`
|
||||
|
||||
| `QdrantConnectionDetails`
|
||||
| Containers of type `QdrantContainer`
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2023 - 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ai.autoconfigure.vectorstore.opensearch;
|
||||
|
||||
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface OpenSearchConnectionDetails extends ConnectionDetails {
|
||||
|
||||
List<String> getUris();
|
||||
|
||||
String getUsername();
|
||||
|
||||
String getPassword();
|
||||
|
||||
}
|
||||
@@ -30,12 +30,19 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@AutoConfiguration
|
||||
@ConditionalOnClass({ OpenSearchVectorStore.class, EmbeddingModel.class, OpenSearchClient.class })
|
||||
@EnableConfigurationProperties(OpenSearchVectorStoreProperties.class)
|
||||
class OpenSearchVectorStoreAutoConfiguration {
|
||||
public class OpenSearchVectorStoreAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(OpenSearchConnectionDetails.class)
|
||||
PropertiesOpenSearchConnectionDetails openSearchConnectionDetails(OpenSearchVectorStoreProperties properties) {
|
||||
return new PropertiesOpenSearchConnectionDetails(properties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@@ -49,12 +56,15 @@ class OpenSearchVectorStoreAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
OpenSearchClient openSearchClient(OpenSearchVectorStoreProperties properties) {
|
||||
HttpHost[] httpHosts = properties.getUris().stream().map(s -> createHttpHost(s)).toArray(HttpHost[]::new);
|
||||
OpenSearchClient openSearchClient(OpenSearchConnectionDetails connectionDetails) {
|
||||
HttpHost[] httpHosts = connectionDetails.getUris()
|
||||
.stream()
|
||||
.map(s -> createHttpHost(s))
|
||||
.toArray(HttpHost[]::new);
|
||||
ApacheHttpClient5TransportBuilder transportBuilder = ApacheHttpClient5TransportBuilder.builder(httpHosts);
|
||||
|
||||
Optional.ofNullable(properties.getUsername())
|
||||
.map(username -> createBasicCredentialsProvider(httpHosts[0], username, properties.getPassword()))
|
||||
Optional.ofNullable(connectionDetails.getUsername())
|
||||
.map(username -> createBasicCredentialsProvider(httpHosts[0], username, connectionDetails.getPassword()))
|
||||
.ifPresent(basicCredentialsProvider -> transportBuilder
|
||||
.setHttpClientConfigCallback(httpAsyncClientBuilder -> httpAsyncClientBuilder
|
||||
.setDefaultCredentialsProvider(basicCredentialsProvider)));
|
||||
@@ -79,4 +89,29 @@ class OpenSearchVectorStoreAutoConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
static class PropertiesOpenSearchConnectionDetails implements OpenSearchConnectionDetails {
|
||||
|
||||
private final OpenSearchVectorStoreProperties properties;
|
||||
|
||||
PropertiesOpenSearchConnectionDetails(OpenSearchVectorStoreProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getUris() {
|
||||
return this.properties.getUris();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return this.properties.getUsername();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return this.properties.getPassword();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -115,6 +115,14 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- OpenSearch Vector Store-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.ai</groupId>
|
||||
<artifactId>spring-ai-opensearch-store</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- test dependencies -->
|
||||
|
||||
<dependency>
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2023 - 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ai.docker.compose.service.connection.opensearch;
|
||||
|
||||
import org.springframework.ai.autoconfigure.vectorstore.opensearch.OpenSearchConnectionDetails;
|
||||
import org.springframework.boot.docker.compose.core.RunningService;
|
||||
import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;
|
||||
import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
class OpenSearchDockerComposeConnectionDetailsFactory
|
||||
extends DockerComposeConnectionDetailsFactory<OpenSearchConnectionDetails> {
|
||||
|
||||
private static final int OPENSEARCH_PORT = 9200;
|
||||
|
||||
protected OpenSearchDockerComposeConnectionDetailsFactory() {
|
||||
super("opensearchproject/opensearch");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected OpenSearchConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {
|
||||
return new OpenSearchDockerComposeConnectionDetails(source.getRunningService());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link OpenSearchConnectionDetails} backed by a {@code OpenSearch}
|
||||
* {@link RunningService}.
|
||||
*/
|
||||
static class OpenSearchDockerComposeConnectionDetails extends DockerComposeConnectionDetails
|
||||
implements OpenSearchConnectionDetails {
|
||||
|
||||
private final OpenSearchEnvironment environment;
|
||||
|
||||
private final String uri;
|
||||
|
||||
OpenSearchDockerComposeConnectionDetails(RunningService service) {
|
||||
super(service);
|
||||
this.environment = new OpenSearchEnvironment(service.env());
|
||||
this.uri = "http://" + service.host() + ":" + service.ports().get(OPENSEARCH_PORT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getUris() {
|
||||
return List.of(this.uri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return "admin";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return this.environment.getPassword();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2023 - 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ai.docker.compose.service.connection.opensearch;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
class OpenSearchEnvironment {
|
||||
|
||||
private final String password;
|
||||
|
||||
OpenSearchEnvironment(Map<String, String> env) {
|
||||
this.password = env.get("OPENSEARCH_INITIAL_ADMIN_PASSWORD");
|
||||
}
|
||||
|
||||
String getPassword() {
|
||||
return this.password;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory=\
|
||||
org.springframework.ai.docker.compose.service.connection.chroma.ChromaDockerComposeConnectionDetailsFactory,\
|
||||
org.springframework.ai.docker.compose.service.connection.ollama.OllamaDockerComposeConnectionDetailsFactory,\
|
||||
org.springframework.ai.docker.compose.service.connection.opensearch.OpenSearchDockerComposeConnectionDetailsFactory,\
|
||||
org.springframework.ai.docker.compose.service.connection.qdrant.QdrantDockerComposeConnectionDetailsFactory,\
|
||||
org.springframework.ai.docker.compose.service.connection.redis.RedisDockerComposeConnectionDetailsFactory,\
|
||||
org.springframework.ai.docker.compose.service.connection.typesense.TypesenseDockerComposeConnectionDetailsFactory,\
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2023 - 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ai.docker.compose.service.connection.opensearch;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.ai.autoconfigure.vectorstore.opensearch.OpenSearchConnectionDetails;
|
||||
import org.springframework.boot.docker.compose.service.connection.test.AbstractDockerComposeIntegrationTests;
|
||||
import org.testcontainers.utility.DockerImageName;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class OpenSearchDockerComposeConnectionDetailsFactoryTests extends AbstractDockerComposeIntegrationTests {
|
||||
|
||||
OpenSearchDockerComposeConnectionDetailsFactoryTests() {
|
||||
super("opensearch-compose.yaml", DockerImageName.parse("opensearchproject/opensearch"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void runCreatesConnectionDetails() {
|
||||
OpenSearchConnectionDetails connectionDetails = run(OpenSearchConnectionDetails.class);
|
||||
assertThat(connectionDetails.getUris()).isNotNull();
|
||||
assertThat(connectionDetails.getUsername()).isEqualTo("admin");
|
||||
assertThat(connectionDetails.getPassword()).isEqualTo("D3v3l0p-ment");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2023 - 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ai.docker.compose.service.connection.opensearch;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class OpenSearchEnvironmentTests {
|
||||
|
||||
@Test
|
||||
void getPasswordWhenNoPassword() {
|
||||
OpenSearchEnvironment environment = new OpenSearchEnvironment(Collections.emptyMap());
|
||||
assertThat(environment.getPassword()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getPasswordWhenHasPassword() {
|
||||
OpenSearchEnvironment environment = new OpenSearchEnvironment(
|
||||
Map.of("OPENSEARCH_INITIAL_ADMIN_PASSWORD", "secret"));
|
||||
assertThat(environment.getPassword()).isEqualTo("secret");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
services:
|
||||
opensearch:
|
||||
image: '{imageName}'
|
||||
ports:
|
||||
- '9200'
|
||||
environment:
|
||||
- OPENSEARCH_INITIAL_ADMIN_PASSWORD=D3v3l0p-ment
|
||||
- discovery.type=single-node
|
||||
@@ -123,6 +123,14 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- OpenSearch Vector Store-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.ai</groupId>
|
||||
<artifactId>spring-ai-opensearch-store</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- test dependencies -->
|
||||
|
||||
<dependency>
|
||||
@@ -216,6 +224,13 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.opensearch</groupId>
|
||||
<artifactId>opensearch-testcontainers</artifactId>
|
||||
<version>2.0.1</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2023 - 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ai.testcontainers.service.connection.opensearch;
|
||||
|
||||
import org.opensearch.testcontainers.OpensearchContainer;
|
||||
import org.springframework.ai.autoconfigure.vectorstore.opensearch.OpenSearchConnectionDetails;
|
||||
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;
|
||||
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
class OpenSearchContainerConnectionDetailsFactory
|
||||
extends ContainerConnectionDetailsFactory<OpensearchContainer<?>, OpenSearchConnectionDetails> {
|
||||
|
||||
@Override
|
||||
public OpenSearchConnectionDetails getContainerConnectionDetails(
|
||||
ContainerConnectionSource<OpensearchContainer<?>> source) {
|
||||
return new OpenSearchContainerConnectionDetails(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link OpenSearchConnectionDetails} backed by a {@link ContainerConnectionSource}.
|
||||
*/
|
||||
private static final class OpenSearchContainerConnectionDetails
|
||||
extends ContainerConnectionDetails<OpensearchContainer<?>> implements OpenSearchConnectionDetails {
|
||||
|
||||
private OpenSearchContainerConnectionDetails(ContainerConnectionSource<OpensearchContainer<?>> source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getUris() {
|
||||
return List.of(getContainer().getHttpHostAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return getContainer().isSecurityEnabled() ? getContainer().getUsername() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return getContainer().isSecurityEnabled() ? getContainer().getPassword() : null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,7 @@ org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFacto
|
||||
org.springframework.ai.testcontainers.service.connection.chroma.ChromaContainerConnectionDetailsFactory,\
|
||||
org.springframework.ai.testcontainers.service.connection.milvus.MilvusContainerConnectionDetailsFactory,\
|
||||
org.springframework.ai.testcontainers.service.connection.ollama.OllamaContainerConnectionDetailsFactory,\
|
||||
org.springframework.ai.testcontainers.service.connection.opensearch.OpenSearchContainerConnectionDetailsFactory,\
|
||||
org.springframework.ai.testcontainers.service.connection.qdrant.QdrantContainerConnectionDetailsFactory,\
|
||||
org.springframework.ai.testcontainers.service.connection.redis.RedisContainerConnectionDetailsFactory,\
|
||||
org.springframework.ai.testcontainers.service.connection.typesense.TypesenseContainerConnectionDetailsFactory,\
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2023 - 2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ai.testcontainers.service.connection.opensearch;
|
||||
|
||||
import org.awaitility.Awaitility;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.opensearch.testcontainers.OpensearchContainer;
|
||||
import org.springframework.ai.autoconfigure.vectorstore.opensearch.OpenSearchVectorStoreAutoConfiguration;
|
||||
import org.springframework.ai.document.Document;
|
||||
import org.springframework.ai.embedding.EmbeddingModel;
|
||||
import org.springframework.ai.transformers.TransformersEmbeddingModel;
|
||||
import org.springframework.ai.vectorstore.OpenSearchVectorStore;
|
||||
import org.springframework.ai.vectorstore.SearchRequest;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
|
||||
@SpringBootTest(properties = {
|
||||
"spring.ai.vectorstore.opensearch.index-name=" + OpenSearchContainerConnectionDetailsFactoryTest.DOCUMENT_INDEX,
|
||||
"spring.ai.vectorstore.opensearch.mapping-json="
|
||||
+ OpenSearchContainerConnectionDetailsFactoryTest.MAPPING_JSON })
|
||||
@Testcontainers
|
||||
class OpenSearchContainerConnectionDetailsFactoryTest {
|
||||
|
||||
@Container
|
||||
@ServiceConnection
|
||||
private static final OpensearchContainer<?> opensearch = new OpensearchContainer<>(
|
||||
"opensearchproject/opensearch:2.12.0");
|
||||
|
||||
static final String DOCUMENT_INDEX = "auto-spring-ai-document-index";
|
||||
|
||||
static final String MAPPING_JSON = "{\"properties\":{\"embedding\":{\"type\":\"knn_vector\",\"dimension\":384}}}";
|
||||
|
||||
private final List<Document> documents = List.of(
|
||||
new Document("1", getText("classpath:/test/data/spring.ai.txt"), Map.of("meta1", "meta1")),
|
||||
new Document("2", getText("classpath:/test/data/time.shelter.txt"), Map.of()),
|
||||
new Document("3", getText("classpath:/test/data/great.depression.txt"), Map.of("meta2", "meta2")));
|
||||
|
||||
@Autowired
|
||||
private OpenSearchVectorStore vectorStore;
|
||||
|
||||
@Test
|
||||
public void addAndSearchTest() {
|
||||
|
||||
vectorStore.add(documents);
|
||||
|
||||
Awaitility.await()
|
||||
.until(() -> vectorStore
|
||||
.similaritySearch(SearchRequest.query("Great Depression").withTopK(1).withSimilarityThreshold(0)),
|
||||
hasSize(1));
|
||||
|
||||
List<Document> results = vectorStore
|
||||
.similaritySearch(SearchRequest.query("Great Depression").withTopK(1).withSimilarityThreshold(0));
|
||||
|
||||
assertThat(results).hasSize(1);
|
||||
Document resultDoc = results.get(0);
|
||||
assertThat(resultDoc.getId()).isEqualTo(documents.get(2).getId());
|
||||
assertThat(resultDoc.getContent()).contains("The Great Depression (1929–1939) was an economic shock");
|
||||
assertThat(resultDoc.getMetadata()).hasSize(2);
|
||||
assertThat(resultDoc.getMetadata()).containsKey("meta2");
|
||||
assertThat(resultDoc.getMetadata()).containsKey("distance");
|
||||
|
||||
// Remove all documents from the store
|
||||
vectorStore.delete(documents.stream().map(Document::getId).toList());
|
||||
|
||||
Awaitility.await()
|
||||
.until(() -> vectorStore
|
||||
.similaritySearch(SearchRequest.query("Great Depression").withTopK(1).withSimilarityThreshold(0)),
|
||||
hasSize(0));
|
||||
}
|
||||
|
||||
private String getText(String uri) {
|
||||
var resource = new DefaultResourceLoader().getResource(uri);
|
||||
try {
|
||||
return resource.getContentAsString(StandardCharsets.UTF_8);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ImportAutoConfiguration(OpenSearchVectorStoreAutoConfiguration.class)
|
||||
static class Config {
|
||||
|
||||
@Bean
|
||||
public EmbeddingModel embeddingModel() {
|
||||
return new TransformersEmbeddingModel();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user