SAP HANA Cloud
Prerequisites
-
您需要一个 SAP HANA Cloud 矢量引擎帐户 - 请参阅 SAP HANA Cloud vector engine - provision a trial account 指南创建试用帐户。
-
You need a SAP HANA Cloud vector engine account - Refer SAP HANA Cloud vector engine - provision a trial account guide to create a trial account.
-
如果需要,一个用于 EmbeddingModel 的 API 密钥,用于生成矢量存储器存储的嵌入。
-
If required, an API key for the EmbeddingModel to generate the embeddings stored by the vector store.
Auto-configuration
Spring AI 不提供用于 SAP Hana 矢量存储器的专用模块。用户需要在使用 Spring AI 中的 SAP Hana 矢量存储器的标准矢量存储器模块 spring-ai-hanadb-store
的应用程序中提供自己的配置。
Spring AI does not provide a dedicated module for SAP Hana vector store.
Users are expected to provide their own configuration in the applications using the standard vector store module for SAP Hana vector store in Spring AI - spring-ai-hanadb-store
.
|
Refer to the Dependency Management section to add the Spring AI BOM to your build file. |
请查看矢量存储器的 HanaCloudVectorStore Properties 列表,了解默认值和配置选项。
Please have a look at the list of hanacloudvectorstore-properties for the vector store to learn about the default values and configuration options.
将Maven Central和/或Snapshot存储库添加到您的构建文件中,请参阅 Artifact Repositories 部分。 |
Refer to the Artifact Repositories section to add Maven Central and/or Snapshot Repositories to your build file. |
此外,您还需要一个配置好的 EmbeddingModel
bean。有关更多信息,请参阅 EmbeddingModel 部分。
Additionally, you will need a configured EmbeddingModel
bean. Refer to the EmbeddingModel section for more information.
HanaCloudVectorStore Properties
您可以在 Spring Boot 配置中使用以下属性来自定义 SAP Hana 矢量存储器。它使用 spring.datasource.
properties to configure the Hana datasource and the spring.ai.vectorstore.hanadb.
属性来配置 Hana 矢量存储器。
You can use the following properties in your Spring Boot configuration to customize the SAP Hana vector store.
It uses spring.datasource.
properties to configure the Hana datasource and the spring.ai.vectorstore.hanadb.
properties to configure the Hana vector store.
Property | Description | Default value |
---|---|---|
|
Driver class name |
com.sap.db.jdbc.Driver |
|
Hana Datasource URL |
- |
|
Hana datasource username |
- |
|
Hana datasource password |
- |
|
TODO |
- |
|
TODO |
- |
|
whether to initialize the required schema |
|
Build a Sample RAG application
演示如何设置一个项目,该项目使用 SAP Hana Cloud 作为矢量数据库并利用 OpenAI 实现 RAG 模式。
Shows how to setup a project that uses SAP Hana Cloud as the vector DB and leverage OpenAI to implement RAG pattern
-
在 SAP Hana DB 中创建表
CRICKET_WORLD_CUP
: -
Create a table
CRICKET_WORLD_CUP
in SAP Hana DB:
CREATE TABLE CRICKET_WORLD_CUP ( _ID VARCHAR2(255) PRIMARY KEY, CONTENT CLOB, EMBEDDING REAL_VECTOR(1536) )
-
在您的
pom.xml
中添加以下依赖项: -
Add the following dependencies in your
pom.xml
您可以将属性 spring-ai-version
设置为 <spring-ai-version>1.0.0-SNAPSHOT</spring-ai-version>
:
You may set the property spring-ai-version
as <spring-ai-version>1.0.0-SNAPSHOT</spring-ai-version>
:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>${spring-ai-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-pdf-document-reader</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-vector-store-hana</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
-
在
application.properties
文件中添加以下属性: -
Add the following properties in
application.properties
file:
spring.ai.openai.api-key=${OPENAI_API_KEY} spring.ai.openai.embedding.options.model=text-embedding-ada-002 spring.datasource.driver-class-name=com.sap.db.jdbc.Driver spring.datasource.url=${HANA_DATASOURCE_URL} spring.datasource.username=${HANA_DATASOURCE_USERNAME} spring.datasource.password=${HANA_DATASOURCE_PASSWORD} spring.ai.vectorstore.hanadb.tableName=CRICKET_WORLD_CUP spring.ai.vectorstore.hanadb.topK=3
Create an Entity
class named CricketWorldCup
that extends from HanaVectorEntity
:
package com.interviewpedia.spring.ai.hana;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.jackson.Jacksonized;
import org.springframework.ai.vectorstore.hanadb.HanaVectorEntity;
@Entity
@Table(name = "CRICKET_WORLD_CUP")
@Data
@Jacksonized
@NoArgsConstructor
public class CricketWorldCup extends HanaVectorEntity {
@Column(name = "content")
private String content;
}
-
创建一个名为
CricketWorldCupRepository
的Repository
,它实现了HanaVectorRepository
接口: -
Create a
Repository
namedCricketWorldCupRepository
that implementsHanaVectorRepository
interface:
package com.interviewpedia.spring.ai.hana;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.transaction.Transactional;
import org.springframework.ai.vectorstore.hanadb.HanaVectorRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public class CricketWorldCupRepository implements HanaVectorRepository<CricketWorldCup> {
@PersistenceContext
private EntityManager entityManager;
@Override
@Transactional
public void save(String tableName, String id, String embedding, String content) {
String sql = String.format("""
INSERT INTO %s (_ID, EMBEDDING, CONTENT)
VALUES(:_id, TO_REAL_VECTOR(:embedding), :content)
""", tableName);
this.entityManager.createNativeQuery(sql)
.setParameter("_id", id)
.setParameter("embedding", embedding)
.setParameter("content", content)
.executeUpdate();
}
@Override
@Transactional
public int deleteEmbeddingsById(String tableName, List<String> idList) {
String sql = String.format("""
DELETE FROM %s WHERE _ID IN (:ids)
""", tableName);
return this.entityManager.createNativeQuery(sql)
.setParameter("ids", idList)
.executeUpdate();
}
@Override
@Transactional
public int deleteAllEmbeddings(String tableName) {
String sql = String.format("""
DELETE FROM %s
""", tableName);
return this.entityManager.createNativeQuery(sql).executeUpdate();
}
@Override
public List<CricketWorldCup> cosineSimilaritySearch(String tableName, int topK, String queryEmbedding) {
String sql = String.format("""
SELECT TOP :topK * FROM %s
ORDER BY COSINE_SIMILARITY(EMBEDDING, TO_REAL_VECTOR(:queryEmbedding)) DESC
""", tableName);
return this.entityManager.createNativeQuery(sql, CricketWorldCup.class)
.setParameter("topK", topK)
.setParameter("queryEmbedding", queryEmbedding)
.getResultList();
}
}
-
现在,创建 REST 控制器类
CricketWorldCupHanaController
,并将ChatModel
和VectorStore
自动注入为依赖项。在此控制器类中,创建以下 REST 端点:-
/ai/hana-vector-store/cricket-world-cup/purge-embeddings
- 从矢量存储器中清除所有嵌入。 -
/ai/hana-vector-store/cricket-world-cup/purge-embeddings
- to purge all the embeddings from the Vector Store -
/ai/hana-vector-store/cricket-world-cup/upload
- 上传 Cricket_World_Cup.pdf,以便其数据作为嵌入存储在 SAP Hana Cloud 矢量数据库中。 -
/ai/hana-vector-store/cricket-world-cup/upload
- to upload the Cricket_World_Cup.pdf so that its data gets stored in SAP Hana Cloud Vector DB as embeddings -
/ai/hana-vector-store/cricket-world-cup
- 使用 Cosine_Similarity in SAP Hana DB 实现RAG
。 -
/ai/hana-vector-store/cricket-world-cup
- to implementRAG
using Cosine_Similarity in SAP Hana DB
-
-
Now, create a REST Controller class
CricketWorldCupHanaController
, and autowireChatModel
andVectorStore
as dependencies In this controller class, create the following REST endpoints:-
/ai/hana-vector-store/cricket-world-cup/purge-embeddings
- 从矢量存储器中清除所有嵌入。 -
/ai/hana-vector-store/cricket-world-cup/purge-embeddings
- to purge all the embeddings from the Vector Store -
/ai/hana-vector-store/cricket-world-cup/upload
- 上传 Cricket_World_Cup.pdf,以便其数据作为嵌入存储在 SAP Hana Cloud 矢量数据库中。 -
/ai/hana-vector-store/cricket-world-cup/upload
- to upload the Cricket_World_Cup.pdf so that its data gets stored in SAP Hana Cloud Vector DB as embeddings -
/ai/hana-vector-store/cricket-world-cup
- 使用 Cosine_Similarity in SAP Hana DB 实现RAG
。 -
/ai/hana-vector-store/cricket-world-cup
- to implementRAG
using Cosine_Similarity in SAP Hana DB
-
package com.interviewpedia.spring.ai.hana;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.SystemPromptTemplate;
import org.springframework.ai.document.Document;
import org.springframework.ai.reader.pdf.PagePdfDocumentReader;
import org.springframework.ai.transformer.splitter.TokenTextSplitter;
import org.springframework.ai.vectorstore.hanadb.HanaCloudVectorStore;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@RestController
@Slf4j
public class CricketWorldCupHanaController {
private final VectorStore hanaCloudVectorStore;
private final ChatModel chatModel;
@Autowired
public CricketWorldCupHanaController(ChatModel chatModel, VectorStore hanaCloudVectorStore) {
this.chatModel = chatModel;
this.hanaCloudVectorStore = hanaCloudVectorStore;
}
@PostMapping("/ai/hana-vector-store/cricket-world-cup/purge-embeddings")
public ResponseEntity<String> purgeEmbeddings() {
int deleteCount = ((HanaCloudVectorStore) this.hanaCloudVectorStore).purgeEmbeddings();
log.info("{} embeddings purged from CRICKET_WORLD_CUP table in Hana DB", deleteCount);
return ResponseEntity.ok().body(String.format("%d embeddings purged from CRICKET_WORLD_CUP table in Hana DB", deleteCount));
}
@PostMapping("/ai/hana-vector-store/cricket-world-cup/upload")
public ResponseEntity<String> handleFileUpload(@RequestParam("pdf") MultipartFile file) throws IOException {
Resource pdf = file.getResource();
Supplier<List<Document>> reader = new PagePdfDocumentReader(pdf);
Function<List<Document>, List<Document>> splitter = new TokenTextSplitter();
List<Document> documents = splitter.apply(reader.get());
log.info("{} documents created from pdf file: {}", documents.size(), pdf.getFilename());
this.hanaCloudVectorStore.accept(documents);
return ResponseEntity.ok().body(String.format("%d documents created from pdf file: %s",
documents.size(), pdf.getFilename()));
}
@GetMapping("/ai/hana-vector-store/cricket-world-cup")
public Map<String, String> hanaVectorStoreSearch(@RequestParam(value = "message") String message) {
var documents = this.hanaCloudVectorStore.similaritySearch(message);
var inlined = documents.stream().map(Document::getText).collect(Collectors.joining(System.lineSeparator()));
var similarDocsMessage = new SystemPromptTemplate("Based on the following: {documents}")
.createMessage(Map.of("documents", inlined));
var userMessage = new UserMessage(message);
Prompt prompt = new Prompt(List.of(similarDocsMessage, userMessage));
String generation = this.chatModel.call(prompt).getResult().getOutput().getContent();
log.info("Generation: {}", generation);
return Map.of("generation", generation);
}
}
由于 HanaDB 矢量存储器支持不提供自动配置模块,您还需要在应用程序中提供矢量存储器 bean,示例如下。
Since HanaDB vector store support does not provide the autoconfiguration module, you also need to provide the vector store bean in your application, as shown below, as an example.
@Bean
public VectorStore hanaCloudVectorStore(CricketWorldCupRepository cricketWorldCupRepository,
EmbeddingModel embeddingModel) {
return HanaCloudVectorStore.builder(cricketWorldCupRepository, embeddingModel)
.tableName("CRICKET_WORLD_CUP")
.topK(1)
.build();
}
-
使用来自维基百科的
contextual
PDF 文件。 -
Use a
contextual
pdf file from wikipedia

使用我们在上一步中创建的文件上传 REST 端点上传此 PDF 文件。
Upload this PDF file using the file-upload REST endpoint that we created in the previous step.