使用Elasticsearch进行更精确的查询
我正在创建一个基于 Elasticsearch 的应用程序,基本上我有一个文档,我会把它提取出来并分成小块,然后我有一个查询:
query = "你们的定价是多少?"
接着我把文本和这个查询放进我的一个函数里:
def construct_enhanced_query(user_query):
keywords = extract_keywords(user_query)
should_clauses = [{"match": {"content": {"query": keyword, "boost": 2}}} for keyword in keywords]
query = {
"query": {
"bool": {
"should": should_clauses,
"minimum_should_match": 1
}
}
}
return query
这个函数叫 extract_keywords()
,大概长这样:
def extract_keywords(text):
doc = nlp(text)
keywords = set([chunk.text for chunk in doc.noun_chunks] + [ent.text for ent in doc.ents])
return keywords
现在问题是,在这些小块里,我有这样的内容:
关于定价 联系我们 了解更多
,还有 定价方案 私人课程 每位学生 $150 30分钟课程 1位老师和1位学生(1:1) 立即预订 半私人课程 每位学生 $130 30分钟课程 1位老师和2位学生(1:2)
。你可以想象,我想提取出 $150 每位学生 这一部分及其相关信息,因为它在同一个小块里,这样是好的。问题是,它只返回了这个:
Document ID: nrIzDI4BhRAP3y-2FwQt Content: PRICING
Document ID: orIzDI4BhRAP3y-2FwQ0 Content: PRICING
Document ID: FLIwDI4BhRAP3y-2UwI2 Content: PRICING
Document ID: GLIwDI4BhRAP3y-2UwJD Content: PRICING
你可以想象,这和查询、关键词搜索以及加权有关。但我想让它更灵活,能够真正提取出相关信息,因为查询不总是“你们的定价是多少”,可能会是其他任何问题,所以我不能把它写死。有什么建议吗?
1 个回答
看起来你想从头开始构建一个语义搜索引擎。Elastic提供了一些功能,可以方便地从外部来源(比如HuggingFace)导入大型语言模型(LLM),并利用这些模型的见解来提升你的搜索效果。
如果你还是想一步一步来,可以先使用一个关键词提取的LLM,把提取的关键词加到你的查询中;或者你可以从一开始就使用嵌入模型,这样查询就可以根据意思来搜索,而不是单纯的词匹配(我在你的例子中推荐这种方法)。
你可以看看文档中的入门指南:https://github.com/elastic/elasticsearch-labs/blob/main/notebooks/search/00-quick-start.ipynb
如果你想了解更多关于语义搜索和词汇搜索的内容,searhlabs上有一些不错的文章:https://www.elastic.co/search-labs/blog/articles/lexical-and-semantic-search-with-elasticsearch
对于你的使用场景,你需要的部分包括:
通过docker导入模型,并设置你的索引和映射(包括一个用于存放嵌入向量的密集向量字段)
运行一个管道或批处理过程,为你索引中的所有文档生成嵌入。
operations = []
for book in books:
operations.append({"index": {"_index": "book_index"}})
# Transforming the title into an embedding using the model
book["title_vector"] = model.encode(book["title"]).tolist()
operations.append(book)
client.bulk(index="book_index", operations=operations, refresh=True)
- 当你用自然语言查询时,比如
query = "你的定价是多少?"
,你需要用同样的模型对这个查询进行嵌入,并把它作为你knn搜索的一部分发送出去:
response = client.search(
index="book_index",
knn={
"field": "title_vector",
"query_vector": model.encode(query),
"k": 10,
"num_candidates": 100,
},
)
希望这些对你有帮助!