精选

Spring AI使用Elasticsearch作为向量数据库

Spring AI 使用 Elasticsearch 作为向量数据库

前言

嗨,大家好,我是汉堡,最近在公司开发 AI 知识库,同时学到了一些 AI 开发相关的技术,这期先与大家分享一下如何用 ES 当做向量数据库。

安装ES

第一步我们先安装 Elasticsearch,这里建议 Elasticsearch 一定要在 8.13.x 以上,这里我选用的版本为 8.14.3。

下载 Docker Desktop

我使用 Docker 部署的 ES,所以需要先安装 Docker Desktop,大家根据自己的系统下载。

Mac 安装 Docker Desktop:https://blog.csdn.net/Andya_net/article/details/127935187

Windows 安装 Docker Desktop:https://zhuanlan.zhihu.com/p/441965046

启动 ES

打开命令行直接一条命令梭哈,ES 自从 8.0 版本就默认开启安全认证了,这里我设置了关闭。

image-20250716215116133

▼
shell
复制代码
docker run -d \ --name elasticsearch \ -p 9200:9200 -p 9300:9300 \ -e "discovery.type=single-node" \ -e "xpack.security.enabled=false" \ -e "xpack.security.http.ssl.enabled=false" \ elasticsearch:8.14.3

访问 http://localhost:9200,出现以下界面代表 ES 启动成功。

image-20250716215136310

部署本地大模型

前往 ollama 官网下载大模型本地部署工具,依旧根据自己系统进行选择。

image-20250716220233449

下载完毕通过命令行下载大模型,大家可以根据电脑配置和需求下载不同的模型和模型参数,qwen、deepseek 都是可以的,我这里就是 8b 的 deepseek-r1

▼
shell
复制代码
ollama run deepseek-r1:8b

image-20250716220427770 然后还要部署一个文本嵌入模型,主要将文本转为向量化,这个模型仅 pull 就好,因为不是文本生成模型 run 不了。

▼
shell
复制代码
ollama pull mxbai-embed-large:latest

搭建 Spring Boot 项目

搭建 Spring Boot 就不用我教了吧,相信各位佐助都会,建议 Spring Boot 版本要在 3.3.x 以上,我的为 3.5.3。

引入依赖

▼
xml
复制代码
<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-elasticsearch-store</artifactId> <version>1.0.0-M6</version> <exclusions> <exclusion> <groupId>co.elastic.clients</groupId> <artifactId>elasticsearch-java</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>co.elastic.clients</groupId> <artifactId>elasticsearch-java</artifactId> <version>8.14.3</version> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-ollama-spring-boot-starter</artifactId> <version>1.0.0-M6</version> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-markdown-document-reader</artifactId> <version>1.0.0-M6</version> </dependency>

添加配置类

ES 配置类,主要配置 ES 连接地址、端口和向量数据的相关参数。

▼
java
复制代码
@Configuration public class EsRagConfig { @Bean public RestClient restClient() { return RestClient.builder(new HttpHost("localhost", 9200, "http")) // 配置 ES 地址和端口 .build(); } @Bean public VectorStore vectorStore(RestClient restClient, EmbeddingModel embeddingModel) { ElasticsearchVectorStoreOptions options = new ElasticsearchVectorStoreOptions(); options.setIndexName("custom-index"); // 设置索引名称 options.setSimilarity(SimilarityFunction.cosine); options.setDimensions(1024); // 设置向量维度 return ElasticsearchVectorStore.builder(restClient, embeddingModel) .options(options) .initializeSchema(true) // 没有索引时自动创建索引 .batchingStrategy(new TokenCountBatchingStrategy()) .build(); } }

Ollama 配置类

将本地大模型注册为 Spring Bean,以后通过 ChatClient 来调用,这样更加自由、定制化。

▼
java
复制代码
@Configuration public class OllamaConfig { @Resource private ChatModel ollamaChatModel; @Resource private LoggerAdvisor loggerAdvisor; @Bean public ChatClient chatClient() { return ChatClient.builder(ollamaChatModel).defaultAdvisors(loggerAdvisor).build(); } }

排除自动配置类

在 Spring Boot类上排除 Elasticsearch 向量存储的自动配置类,不然会打架。

▼
java
复制代码
@SpringBootApplication(exclude = {ElasticsearchVectorStoreAutoConfiguration.class}) //排除 Elasticsearch 向量存储的自动配置类 @MapperScan("com.hjj.knowledgebase.mapper") @EnableScheduling @EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true) public class MainApplication { public static void main(String[] args) { SpringApplication.run(MainApplication.class, args); } }

配置文件和知识库文件

主要指定 ollama 地址和本地模型,以及端口号和请求前缀

▼
yaml
复制代码
spring: ai: ollama: base-url: http://localhost:11434 chat: model: deepseek-r1:8b server: address: 0.0.0.0 port: 8888 servlet: context-path: /api

添加 Markdown 读取工具和 Markdown 文件

▼
java
复制代码
@Component public class MyMarkdownReader { private final Resource resource; public MyMarkdownReader(@Value("classpath:自我介绍.md") Resource resource) { this.resource = resource; } public List<Document> loadMarkdown() { MarkdownDocumentReaderConfig config = MarkdownDocumentReaderConfig.builder() .withHorizontalRuleCreateDocument(true) .withIncludeCodeBlock(false) .withIncludeBlockquote(false) .withAdditionalMetadata("filename", "code.md") .build(); MarkdownDocumentReader reader = new MarkdownDocumentReader(this.resource, config); return reader.get(); } }

在 resources 目录放一个要存到向量数据库的文件。

image-20250716223134562

Markdown 文件内容如下:

image-20250716225147974

新建一个 RagController

▼
java
复制代码
@RestController @RequestMapping("/rag") public class RagController implements CommandLineRunner { @Resource private ChatClient chatClient; @Resource private ElasticsearchVectorStore vectorStore; @Resource private MyMarkdownReader myMarkdownReader; @Override public void run(String... args) throws Exception { List<Document> documents = myMarkdownReader.loadMarkdown(); vectorStore.add(documents); System.out.println("文档写入 ES 成功"); } @GetMapping("/completion") public String completion(@RequestParam String question) { return chatClient.prompt() .user(question) .advisors(new QuestionAnswerAdvisor(vectorStore)) .call() .content(); } }

到这基本就 OK 了,随后启动项目,查看文件已经写入成功没,再通过 ES 调接口,查看是不是真的存储成功,可以看到真的成了。

image-20250716223208461

image-20250716224214356

调用结果如下:

image-20250716224152260

总结

本文只是实现的一个小 demo,适合小文本场景,对于大文本场景通常需要 ETL (提取

转换和加载)、token 切分,Rag 相似度匹配,条件过滤,而对于有图片的文件还需要实现 OCR。如果觉得文章不错的话,就给我点个赞吧,嘿嘿😋。Spring 官方还提供了各种文件的 reader,可以根据需求和场景选择合适的 reader,例如 tika 能实现 html、doc、ppt 和 pdf 多种文件的读取,但是对于 pdf 文件个人不太建议使用 tika 库,要想学习更多知识就请关注我吧❤️。

image-20250716225000509

个人项目

厚米匹配

网址:http://hm.hejiajun.icu/

前端仓库:https://github.com/dnwwdwd/homieMatching-fronted

后端仓库:https://github.com/dnwwdwd/homieMatching

灵犀 BI

网址:http://bi.hejiajun.icu/

前端仓库:https://github.com/dnwwdwd/Lingxi-BI-fronted

后端仓库:https://github.com/dnwwdwd/Lingxi-BI

0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
吃遍全国汉堡
作者分享
GPT发癫了,我也没聊彩票啊
3
可以转战Claude订阅了,GPT发布延迟还被吊着打,甚至不如去订阅国产 AI 聚合套餐
4
Notus 正式发布:我做了一个真正属于自己的 AI 知识库
6
Notus太强了,点赞
3
这篇文章我十分赞同,GPT 给我的感觉就是不够灵性、不够聪明,必须要给明确的目标和指定任务才能干的好,倘若任务十分发散开放就变得十分糖。相比之下 Claude 就非常有灵性,它总是能看透用户意图抓到用户实际需要什么,特别是在做调研类任务时 Claude 显得更强,GPT 总是 get 不到我的点,我让它找啥它才找啥,很难把我提出每个需求串起来去找,这就很难受。好在GPT 6 Astra 好了不少,但是太贵了。 https://chatgpt.com/share/6ab08cbd-982c-83e8-8d49-02d6006e75e8 这个对话就是一个活生生的例子,我想找一个可以查看各家coding agent额度的项目,通过官方OAuth登录进行登录认证,而不是读取auth.json等权限文件,因为我想搬砖到懒猫微服上去。但这个 GPT 气得我没话说,我把所有需求说明白了,它找出个dsh 插件来了https://github.com/lninghaha/dsh-coding-subscription-oauth 最后跟我说没找到,还是我告诉它有个项目能符合我的要求才开始分析(实际我并没让它分析,我只是问他合不合适,分析过程中它还说了如何去搬到懒猫微服,因为 GPT 记忆中知道搬到懒猫微服的前提是什么,其中条件之一必须是web端架构且不依赖于其他任何项目,是一个独立的项目个体,但它还是能找出 dsh 插件来搪塞我)。 更别说其他的工作,比如调整UI、写文案等。X 上有个帖子说的很好,我让 GPT 调整网页的文案或者按钮的位置,比如我希望把登录功能作为单独的页面展示而不是弹窗,它会非常脑残得在登录页面底部写上“登录功能已作为单独页面展示,而不是弹窗”,如果你经历过肯定知道我在说什么。 还有codex的多agent协作非常的垃圾,主agent不信任sub-agent的执行结果,非要自己去验证,导致之前我本来想写一个文章介绍如何进行多agent实战,但它耗了我2个重置机会连第一个阶段都没进行完,一共有6阶段。而且 GPT 的重置就是个骗局,因为不断重置你很难判断一周内套餐实际能用多少的token量,从而官方可以不断的削减使用量,而且因为不断重置模型不断降智,速度也很慢。
8
下载 APP