语义搜索
什么是语义搜索?
语义搜索是一种使用 NLP 理解搜索查询的意图和上下文含义的技术。这允许返回与用户意图相关的结果,即使查询不包含确切的关键词。
它是如何工作的?
我们使用诸如 sentence-transformers 之类的文本嵌入模型,将您的文本转换为捕获语义信息的向量。这些向量表示句子的上下文含义。当用户发出搜索查询时,我们将他们的查询编码成向量并搜索类似的文档。
索引文档
我们将依靠 Elasticsearch 来将某些文档字段转换为向量以及将用户的查询转换为向量。
我们将索引 4000 部电影,并对 plot
字段进行向量化。
将嵌入模型加载到 Elasticsearch 中
在这个例子中,我们将使用来自 MiniLM-L6-v2 (在新标签页中打开) 的 sentence-transformers (在新标签页中打开) 库。
按照此 笔记本 (在新标签页中打开) 执行以下步骤。
在笔记本的最后,您将拥有
- 在 Elasticsearch 中运行的嵌入模型
- 一个索引,它具有一个推理管道,该管道使用嵌入模型将
plot
字段转换为向量 - 4000 部电影已摄入索引,并且
plot
字段已转换为向量
创建 Searchkit 应用
我们将克隆 Next.js 示例应用并将其用作起点。
curl https://codeload.github.com/searchkit/searchkit/tar.gz/main | \
tar -xz --strip=2 searchkit-main/examples/with-semantic-search-nextjs
安装依赖项
在项目的根目录中,安装依赖项
yarn
配置 Searchkit
我们将配置 Searchkit 以连接到 Elasticsearch。这取决于 Elasticsearch 的托管方式。在这个例子中,我们使用的是 Elastic Cloud。
const apiClient = API(
{
connection: {
host: '<elasticsearch-host>',
apiKey: '<api-key>'
},
search_settings: { ... }
}
)
更新显示字段
在这个例子中,我们显示了 title
和 plot
字段。
const apiClient = API(
{
connection: { ... },
search_settings: {
search_attributes: [],
result_attributes: ['title', 'Plot'],
}
}
)
以及在 Hits
组件中
const HitView = (props: any) => {
return (
<div>
<div className="hit__details">
<h2>
{props.hit.title}
</h2>
{props.hit.Plot}
</div>
</div>
);
};
配置 Searchkit 查询
现在我们需要更新 Searchkit 的查询以使用执行向量搜索而不是常规搜索。
export async function POST(req: NextRequest, res: NextResponse) {
const data = await req.json()
const results = await apiClient.handleRequest(data, {
// false to disable keyword search
getQuery: () => false,
getKnnQuery: (query) => {
return {
field: 'plot_embedding.predicted_value',
k: 10,
num_candidates: 50,
query_vector_builder: {
text_embedding: {
model_id: 'sentence-transformers__all-minilm-l6-v2',
model_text: query
}
}
}
}
})
return NextResponse.json(results)
}
运行应用
yarn dev
混合搜索
在这个例子中,我们使用向量搜索来返回最相关的结果。但是,我们也可以将其与常规关键词搜索结合起来,以返回最相关的匹配查询的结果。
我们首先在 search_settings
配置中定义 search_attributes
。
const apiClient = API(
{
connection: { ... },
search_settings: {
search_attributes: ['title', 'Plot'],
result_attributes: ['title', 'Plot'],
}
}
)
然后我们从 handleRequest
调用中删除 getQuery
函数。
在下面的示例中,当客户搜索时,将同时调用默认的 getQuery 和 getKnnQuery。来自两个查询的结果将合并并返回给客户。
我们还将 rrf
参数发送到 Elasticsearch 以平衡来自两个查询的不同分数。
export async function POST(req: NextRequest, res: NextResponse) {
const data = await req.json()
const results = await apiClient.handleRequest(data, {
getKnnQuery: (query) => {
return {
field: 'plot_embedding.predicted_value',
k: 10,
num_candidates: 50,
query_vector_builder: {
text_embedding: {
model_id: 'sentence-transformers__all-minilm-l6-v2',
model_text: query
}
}
}
}
})
return NextResponse.json(results)
}