当前位置: 首页 > news >正文

Milvus + Ollama 实战:5分钟搭建本地文本搜索引擎(Java版)

Milvus + Ollama 实战:5分钟搭建本地文本搜索引擎(Java版)

在当今信息爆炸的时代,快速准确地检索文本内容已成为开发者面临的常见挑战。传统的关键词匹配搜索方式往往难以满足语义相似度的需求,而基于向量搜索的技术正逐渐成为解决这一问题的利器。本文将带你使用Milvus向量数据库和Ollama文本嵌入工具,通过Java快速构建一个本地文本搜索引擎。

1. 环境准备与工具介绍

搭建本地文本搜索引擎前,我们需要准备两个核心组件和一个开发环境:

  • Milvus:专为向量搜索优化的开源数据库,支持亿级向量的毫秒级检索
  • Ollama:本地运行的文本嵌入模型服务,可将文本转换为高维向量
  • Java开发环境:推荐JDK 11+和Maven 3.6+

安装过程非常简单:

# 安装Milvus(使用Docker方式) docker pull milvusdb/milvus:v2.4.0 docker run -d --name milvus -p 19530:19530 milvusdb/milvus:v2.4.0 # 安装Ollama(Mac/Linux) curl -fsSL https://ollama.com/install.sh | sh ollama pull nomic-embed-text

提示:Windows用户可通过WSL2运行Ollama,Milvus安装方式与Linux一致

2. 项目初始化与依赖配置

创建一个标准的Maven项目,添加以下关键依赖到pom.xml:

<dependencies> <!-- Milvus Java SDK --> <dependency> <groupId>io.milvus</groupId> <artifactId>milvus-sdk-java</artifactId> <version>2.4.0</version> </dependency> <!-- HTTP客户端 --> <dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> <version>4.12.0</version> </dependency> <!-- JSON处理 --> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.10.1</version> </dependency> </dependencies>

基础配置类应包含以下常量:

public class Config { // Milvus配置 public static final String MILVUS_HOST = "localhost"; public static final int MILVUS_PORT = 19530; public static final String MILVUS_TOKEN = "root:Milvus"; // Ollama配置 public static final String OLLAMA_URL = "http://localhost:11434/v1/embeddings"; public static final String EMBEDDING_MODEL = "nomic-embed-text"; // 集合配置 public static final String COLLECTION_NAME = "text_search"; public static final int VECTOR_DIMENSION = 768; }

3. 核心功能实现

3.1 向量存储模块

首先创建Milvus集合,定义包含三个字段的schema:

  1. id:主键字段(Int64)
  2. content:原始文本(VarChar)
  3. vector:文本向量(FloatVector)
public class VectorStorage { private final MilvusClientV2 client; public VectorStorage() { ConnectConfig connectConfig = ConnectConfig.builder() .uri("http://" + Config.MILVUS_HOST + ":" + Config.MILVUS_PORT) .token(Config.MILVUS_TOKEN) .build(); this.client = new MilvusClientV2(connectConfig); } public void createCollection() { // 构建字段schema CreateCollectionReq.CollectionSchema schema = client.createSchema(); schema.addField(AddFieldReq.builder() .fieldName("id") .dataType(DataType.Int64) .isPrimaryKey(true) .autoID(true) .build()); schema.addField(AddFieldReq.builder() .fieldName("content") .dataType(DataType.VarChar) .maxLength(1000) .build()); schema.addField(AddFieldReq.builder() .fieldName("vector") .dataType(DataType.FloatVector) .dimension(Config.VECTOR_DIMENSION) .build()); // 创建索引 IndexParam vectorIndex = IndexParam.builder() .fieldName("vector") .indexType(IndexParam.IndexType.AUTOINDEX) .metricType(IndexParam.MetricType.COSINE) .build(); // 创建集合 CreateCollectionReq createReq = CreateCollectionReq.builder() .collectionName(Config.COLLECTION_NAME) .collectionSchema(schema) .indexParams(Collections.singletonList(vectorIndex)) .build(); client.createCollection(createReq); } }

3.2 文本向量化服务

通过Ollama API将文本转换为向量:

public class TextEmbedder { private static final Gson gson = new Gson(); private final OkHttpClient httpClient; public TextEmbedder() { this.httpClient = new OkHttpClient(); } public float[] embedText(String text) throws IOException { JsonObject requestBody = new JsonObject(); requestBody.add("input", gson.toJsonTree(new String[]{text})); requestBody.addProperty("model", Config.EMBEDDING_MODEL); Request request = new Request.Builder() .url(Config.OLLAMA_URL) .post(RequestBody.create( requestBody.toString(), okhttp3.MediaType.parse("application/json") )) .build(); try (Response response = httpClient.newCall(request).execute()) { if (!response.isSuccessful()) { throw new IOException("请求失败: " + response.code()); } JsonObject jsonResponse = gson.fromJson( response.body().string(), JsonObject.class ); JsonArray embedding = jsonResponse.getAsJsonArray("data") .get(0).getAsJsonObject() .getAsJsonArray("embedding"); float[] vector = new float[embedding.size()]; for (int i = 0; i < embedding.size(); i++) { vector[i] = embedding.get(i).getAsFloat(); } return vector; } } }

3.3 数据导入与搜索实现

实现文本数据的批量导入和相似度搜索功能:

public class SearchEngine { private final VectorStorage storage; private final TextEmbedder embedder; public SearchEngine() { this.storage = new VectorStorage(); this.embedder = new TextEmbedder(); } public void indexDocuments(List<String> documents) { List<JsonObject> insertData = new ArrayList<>(); for (String doc : documents) { try { float[] vector = embedder.embedText(doc); JsonObject item = new JsonObject(); item.addProperty("content", doc); item.add("vector", gson.toJsonTree(vector)); insertData.add(item); } catch (IOException e) { System.err.println("文本向量化失败: " + e.getMessage()); } } InsertReq insertReq = InsertReq.builder() .collectionName(Config.COLLECTION_NAME) .data(insertData) .build(); storage.getClient().insert(insertReq); } public List<String> searchSimilar(String query, int topK) { try { float[] queryVector = embedder.embedText(query); SearchReq searchReq = SearchReq.builder() .collectionName(Config.COLLECTION_NAME) .data(Collections.singletonList(new FloatVec(queryVector))) .topK(topK) .outputFields(Collections.singletonList("content")) .build(); SearchResp resp = storage.getClient().search(searchReq); return resp.getSearchResults().stream() .flatMap(Collection::stream) .map(result -> result.getEntity().get("content").getAsString()) .collect(Collectors.toList()); } catch (IOException e) { System.err.println("搜索失败: " + e.getMessage()); return Collections.emptyList(); } } }

4. 实战应用与性能优化

4.1 完整使用示例

下面是一个从初始化到搜索的完整流程:

public class Demo { public static void main(String[] args) { // 初始化引擎 SearchEngine engine = new SearchEngine(); // 创建集合(首次运行) engine.getStorage().createCollection(); // 准备测试数据 List<String> documents = Arrays.asList( "Milvus是一个开源的向量数据库", "Ollama可以在本地运行大语言模型", "向量搜索比传统关键词搜索更理解语义", "Java是最流行的编程语言之一" ); // 导入数据 engine.indexDocuments(documents); System.out.println("数据导入完成"); // 执行搜索 String query = "有哪些好用的向量数据库"; List<String> results = engine.searchSimilar(query, 2); System.out.println("与'" + query + "'最相似的结果:"); results.forEach(System.out::println); } }

4.2 性能优化技巧

根据实际测试经验,以下方法可以显著提升系统性能:

  1. 批量处理:将多个文本组合成一个batch发送给Ollama
public List<float[]> batchEmbed(List<String> texts) { // 将多个文本组合成一个请求 JsonObject requestBody = new JsonObject(); requestBody.add("input", gson.toJsonTree(texts)); // ...其余处理逻辑 }
  1. 连接池配置:优化Milvus客户端连接
ConnectConfig connectConfig = ConnectConfig.builder() .uri(milvusUri) .token(token) .connectTimeout(10, TimeUnit.SECONDS) // 连接超时 .keepAliveTimeout(30, TimeUnit.SECONDS) // 保持连接 .build();
  1. 索引调优:根据数据规模选择合适的索引类型
数据规模推荐索引类型适用场景
<10万FLAT精确搜索
10-100万IVF_FLAT平衡精度与速度
>100万HNSW大规模数据

4.3 常见问题排查

遇到问题时,可以按照以下步骤检查:

  1. 连接问题

    • 确认Milvus服务是否运行:docker ps | grep milvus
    • 检查端口是否开放:telnet localhost 19530
  2. 向量维度不匹配

    • 确保Ollama输出的维度与Milvus集合定义一致
    • 不同模型输出维度参考:
      • nomic-embed-text: 768
      • all-minilm: 384
  3. 性能瓶颈

    • 使用time命令测量各阶段耗时
    • 考虑在Milvus中启用分区功能处理大数据集
http://www.jsqmd.com/news/552017/

相关文章:

  • STM32F10x Flash模拟EEPROM原理与AN2594实战指南
  • STM32智能安全头盔系统设计与实现
  • seo优化词在网站优化中的地位是什么
  • 突破Windows系统限制:Interceptor驱动级输入模拟技术实战指南
  • 2026年安徽暖气片选购指南:五大高评价服务商深度测评与选型策略 - 2026年企业推荐榜
  • Gemma-3-12b-it多模态推理教程:如何评估模型对图像隐含信息的理解深度
  • Win10资源管理器默认打开‘此电脑‘设置教程(含快速访问彻底关闭方法)
  • 基于扩张状态观测器的永磁同步电机PWM电流预测控制:EI论文复现之旅
  • AD20/Altium designer——元器件批量命名与编号的高效技巧
  • 5步掌握音频特征图谱生成:从零基础到专业分析
  • 网易云音乐Discord同步工具完整指南:在Discord实时展示你的音乐品味
  • Dirsearch实战指南:从Docker部署到高级扫描技巧
  • 脱硫治理新标杆:2026年唐山地区五大技术型服务商深度解析 - 2026年企业推荐榜
  • STM32G474实战:3种RS485通信方式对比(轮询/中断/DMA)
  • Johnson算法在流水线作业调度中的优化实践
  • 2026年安徽3+2分段制学校优选:深度解析合肥腾飞学校的教学实力与升学路径 - 2026年企业推荐榜
  • 避开这两个坑!用ADC0808给51单片机做宽电压测量(2.1-25V)的Proteus仿真心得
  • (技术解析)小波卷积WTConv:频域即插即用,如何让CNN“视野”更广、参数更省?
  • 5G随机接入过程实战:如何用TS38.300标准优化UE连接速度(附配置示例)
  • STM32智能车库管理系统设计与实现
  • Jetson Nano蓝牙音频实战:从适配器选型到完美配对
  • 从不同模型视角看岩石压缩:PFC、GBM与3D模型的碰撞
  • 2026深圳正规仿真树与仿木栏杆服务商推荐榜:仿真假山/仿真大树/仿真树/仿真溶洞/假树/塑石假山/水泥仿木栏杆/选择指南 - 优质品牌商家
  • BabelDOC:突破性PDF智能翻译工具,让学术文档跨越语言障碍
  • 嵌入式操作系统面试高频考点解析
  • Async1Wire异步1-Wire驱动库:DS18B20非阻塞温度采集方案
  • 从零到一:基于STM32F103C8T6与CH340的USART串口通信实战指南
  • 2026家用升降设备优质产品推荐榜:小型升降平台、小型升降机、曳引式别墅电梯、杂物电梯、液压升降平台、液压升降机选择指南 - 优质品牌商家
  • 2026年河北铝艺围栏选购指南:五大实力厂商深度解析与可靠之选 - 2026年企业推荐榜
  • 2026江苏代理记账行业深度测评:揭秘五强服务商与源头工厂选择逻辑 - 2026年企业推荐榜