一、 引言:超越LIKE的智能搜索
在知识库、电商平台、内容推荐等场景中,用户往往无法用精确的关键词描述需求。例如,用户可能搜索“适合雨天听的舒缓音乐”,而非简单的“轻音乐”。传统的LIKE或全文索引基于词法匹配,难以理解这种语义意图。
解决方案是文本嵌入向量。大模型可以将文本转换为高维空间中的向量(一组浮点数),语义相似的文本其向量在空间中的距离也更近。通过计算向量距离(如余弦相似度),就能实现“意思上”的搜索。
近年来,主流数据库纷纷增加对向量类型的原生支持。MySQL 8.0.31及以上版本通过VECTOR数据类型和相应的距离函数,使开发者能在熟悉的MySQL生态中直接进行向量运算,无需引入额外的向量数据库,极大简化了技术架构。
二、 环境准备与数据库配置
- 前提条件
MySQL Server版本 >= 8.0.31
确认已安装MySQL Vector扩展(通常是默认包含的)
Java 17及以上
Spring Boot 3.x
- 创建支持向量的数据库表
我们以products产品表为例,为其增加语义搜索能力。
sql
-- 创建数据库
CREATE DATABASE ai_shop CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE ai_shop;
-- 创建产品表,并新增向量字段
CREATE TABLE products (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL COMMENT '产品名称',
description TEXT COMMENT '产品描述',
-- 新的向量字段:用于存储description的文本嵌入向量
-- 1536维度适配OpenAI的text-embedding-3-small模型
description_vector VECTOR(1536) NOT NULL,
-- 为向量字段创建索引以加速搜索
INDEX description_vector_idx (description_vector) USING VECTOR
) COMMENT='产品表(带向量搜索)';
-- 创建一个函数来简化余弦相似度计算
CREATE FUNCTION cosine_similarity(a VECTOR, b VECTOR) RETURNS FLOAT
DETERMINISTIC
RETURN COSINE_SIMILARITY(a, b);
关键点说明:
VECTOR(1536):定义了一个1536维的向量字段,维度需与所选嵌入模型匹配。
USING VECTOR:指定为该向量字段创建专门的向量索引。
COSINE_SIMILARITY:MySQL内置的余弦相似度计算函数,值越接近1,相似度越高。
三、 Java应用集成
- 项目依赖(pom.xml)
除了Spring Boot基础依赖,我们还需要MySQL驱动、JDBC以及OpenAI客户端。
xml
org.springframework.boot
spring-boot-starter-data-jdbc
com.mysql
mysql-connector-j
runtime
dev.langchain4j
langchain4j
0.29.0
dev.langchain4j
langchain4j-open-ai
0.29.0
- 应用配置(application.yml)
yaml
spring:
datasource:
url: jdbc:mysql://localhost:3306/ai_shop?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: your_username
password: your_password
openai:
api-key: ${OPENAI_API_KEY}
embedding-model: text-embedding-3-small
- 核心实体与Repository
定义与数据库表映射的实体类。这里我们使用Spring Data JDBC,因其对自定义类型映射更为灵活。
java
// Product.java - 实体类
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.Table;
@Table("products")
public class Product {
@Id
private Long id;
private String name;
private String description;
// 重点:向量字段的映射
// MySQL JDBC驱动会将float数组与VECTOR类型自动转换
@Column("description_vector")
private float[] descriptionVector;
// 构造器、Getter和Setter省略...
}
java
// ProductRepository.java - 数据访问层
import org.springframework.data.jdbc.repository.query.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import java.util.List;
public interface ProductRepository extends CrudRepository {
/**
* 核心语义搜索查询
* 使用余弦相似度,并按相似度得分从高到低排序
* :queryVector 是由用户查询文本通过AI模型转换而来的向量
*/
@Query("""
SELECT id, name, description, description_vector,
cosine_similarity(description_vector, :queryVector) AS similarity_score
FROM products
WHERE cosine_similarity(description_vector, :queryVector) > :minScore
ORDER BY similarity_score DESC
LIMIT :limit
""")
List<SearchResult> semanticSearch(@Param("queryVector") float[] queryVector,
@Param("minScore") double minScore,
@Param("limit") int limit);
// 定义一个接口来接收包含相似度得分的查询结果
interface SearchResult {
Long getId();
String getName();
String getDescription();
double getSimilarityScore(); // 计算得到的相似度得分
}
}
- 语义搜索服务
该服务负责将用户查询文本转换为向量,并调用Repository进行搜索。
java
// SemanticSearchService.java
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.openai.OpenAiEmbeddingModel;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class SemanticSearchService {
private final ProductRepository productRepository;
private final EmbeddingModel embeddingModel; // 文本嵌入模型
public SemanticSearchService(ProductRepository productRepository) {
this.productRepository = productRepository;
// 初始化嵌入模型(例如OpenAI)
this.embeddingModel = OpenAiEmbeddingModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName("text-embedding-3-small")
.build();
}
/**
* 执行语义搜索
* @param query 用户查询文本(如:“想要一个续航久的蓝牙耳机”)
* @param minScore 相似度阈值(0到1之间,如0.75)
* @param limit 返回结果数量
* @return 按相似度排序的产品列表
*/
public List<ProductRepository.SearchResult> search(String query, double minScore, int limit) {
// 1. 将查询文本转换为向量
float[] queryVector = convertTextToVector(query);
// 2. 执行向量相似度搜索
return productRepository.semanticSearch(queryVector, minScore, limit);
}
private float[] convertTextToVector(String text) {
// 使用EmbeddingModel获取文本的向量表示
dev.langchain4j.data.embedding.Embedding embedding = embeddingModel.embed(text).content();
// 将Embedding对象转换为float数组
// 注意:LangChain4j的Embedding内部是float数组,但需确认维度匹配
return embedding.vector();
}
/**
* 添加新产品时,自动为其描述生成向量并存储
*/
public void addProduct(Product product) {
float[] vector = convertTextToVector(product.getDescription());
product.setDescriptionVector(vector);
productRepository.save(product);
}
}
- REST控制器
java
// SearchController.java
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/search")
public class SearchController {
private final SemanticSearchService searchService;
public SearchController(SemanticSearchService searchService) {
this.searchService = searchService;
}
@PostMapping("/semantic")
public List<ProductRepository.SearchResult> semanticSearch(@RequestBody SearchRequest request) {
return searchService.search(request.query(), 0.7, 10); // 阈值0.7,返回10条
}
@PostMapping("/product")
public Product addProduct(@RequestBody Product product) {
searchService.addProduct(product);
return product;
}
public record SearchRequest(String query) {}
}
四、 测试与性能优化
- 测试流程
向/api/search/product POST一个产品:{"name": "无线蓝牙耳机", "description": "这款耳机拥有超长续航30小时,音质纯净,佩戴舒适,适合运动和通勤。"}
向/api/search/semantic POST一个查询:{"query": "有没有能长时间使用不用充电的耳机推荐?"}
观察返回结果,即使没有完全匹配的关键词,也能凭借语义相似度找到正确产品。
- 性能优化建议
索引优化:确保description_vector字段上已创建向量索引。
维度选择:在精度和性能间权衡。OpenAI的text-embedding-3-small模型(1536维)在性能和效果上是不错的选择。
分区与分片:对于海量数据,可考虑按业务分区或使用MySQL分片来减少单次搜索的数据量。
近似最近邻搜索:对于亿级数据,精确的近邻搜索成本高。可关注未来MySQL对HNSW等近似算法的支持。
五、 总结
通过MySQL的Vector扩展,我们成功地将AI驱动的语义搜索能力无缝集成到了最经典的关系型数据库和Java应用栈中。这种方案的优势在于:
架构简化:无需引入和维护独立的向量数据库,降低系统复杂度。
事务一致性:向量数据和业务数据在同一数据库事务中保持一致。
技术栈统一:Java开发者可以使用熟悉的JDBC/MyBatis/Spring Data等工具进行操作。
随着数据库对AI原生支持能力的不断加强,将向量计算下推到数据层已成为明显趋势。这为Java应用处理非结构化数据、构建更智能的搜索和推荐系统开辟了新的可能性。