admin管理员组文章数量:1438284
如何使用ES的同义词API自动化同义词生成和上传
为了提供高效的用户体验,提升搜索结果的质量至关重要。优化搜索的一种方法是通过同义词自动扩展查询词。这种方式可以更广泛地解释查询,涵盖语言变化,从而提高结果匹配的准确性。
本文探讨了如何使用大语言模型(LLM)自动识别和生成同义词,并将这些词以编程方式加载到Elasticsearch的同义词API中。
什么时候使用同义词?
使用同义词可以成为比向量搜索更快捷和经济高效的解决方案。其实现更为简单,因为不需要深入了解嵌入或复杂的向量摄取过程。此外,资源消耗也较低,因为向量搜索需要更大的存储容量和内存来进行嵌入索引和检索。
另一个重要方面是搜索的区域化。通过同义词,可以根据当地语言和习惯调整术语。这在嵌入可能无法匹配区域表达或特定国家术语的情况下非常有用。例如,一些词或缩写可能在不同地区有不同的含义,但对当地用户来说自然被视为同义词。在巴西,这种情况很常见。"Abacaxi" 和 "ananás" 都是菠萝,但第二个词在东北的一些地区更常使用。同样,东南地区著名的“pão francês”在东北可能被称为“pão careca”。
如何使用LLM生成同义词?
为了自动获取同义词,我们可以使用LLM,这些模型通过分析术语的上下文来建议合适的变体。这种方法允许动态扩展同义词,确保更广泛和准确的搜索,而不依赖固定词典。
在这个演示中,我们将使用LLM为电商产品生成同义词。许多搜索由于查询词的变化而返回很少甚至没有结果。通过同义词,我们可以解决这个问题。例如,搜索“智能手机”可以涵盖不同型号的手机,确保用户找到他们想要的产品。
预备条件
开始之前,我们需要设置环境并定义所需的依赖项。我们将使用Elastic提供的解决方案在Docker中本地运行Elasticsearch和Kibana。代码将用Python v3.9.6编写,并需以下依赖:
代码语言:bash复制pip install openai==1.59.8 elasticsearch==8.15.1
创建产品索引
最初,我们将创建一个不支持同义词的产品索引。这将允许我们验证查询,然后与包含同义词的索引进行比较。
在Kibana DevTools中使用以下命令批量加载产品数据集来创建索引:
代码语言:json复制POST _bulk
{"index": {"_index": "products", "_id": 10001}}
{"category": "Electronics", "name": "iPhone 14 Pro"}
{"index": {"_index": "products", "_id": 10007}}
{"category": "Electronics", "name": "MacBook Pro 16-inch"}
{"index": {"_index": "products", "_id": 10013}}
{"category": "Electronics", "name": "Samsung Galaxy Tab S8"}
...
使用LLM生成同义词
在这一步中,我们将使用LLM动态生成同义词。为此,我们将集成OpenAI API,定义合适的模型和提示。LLM将接收产品的类别和名称,确保同义词在上下文中相关。
代码语言:python代码运行次数:0运行复制import json
import logging
from openai import OpenAI
def call_gpt(prompt, model):
try:
logging.info("通过LLM生成同义词...")
response = client.chatpletions.create(
model=model,
messages=[{"role": "user", "content": prompt}],
temperature=0.7,
max_tokens=1000
)
content = response.choices[0].message.content.strip()
return content
except Exception as e:
logging.error(f"使用模型失败: {e}")
return None
def generate_synonyms(category, products):
synonyms = {}
for product in products:
prompt = (
f"你是产品同义词生成专家。根据提供的类别和产品名称生成同义词或相关术语。请遵循以下规则:\n"
f"1. **格式**:第一个词应为主要项目(产品名称的一部分,排除品牌),后跟最多3个用逗号分隔的同义词。\n"
f"2. **排除品牌**:同义词中不要包含品牌名称。\n"
f"3. **同义词数量**:每个产品最多生成3个同义词。\n\n"
f"类别为:**{category}**,产品为:**{product}**。只返回请求格式的同义词,不要附加解释。"
)
response = call_gpt(prompt, "gpt-4o")
synonyms[product] = response
return synonyms
从创建的产品索引中,我们将检索“Electronics”类别下的所有商品,并将其名称发送给LLM。预期输出可能类似于:
代码语言:json复制{
"iPhone 14 Pro": ["iPhone", "smartphone", "mobile", "handset"],
"MacBook Pro 16-inch": ["MacBook", "Laptop", "Notebook", "Ultrabook"],
...
}
借助生成的同义词,我们可以使用Synonyms API将它们注册到Elasticsearch中。
使用Synonyms API管理同义词
Synonyms API提供了一种在系统内直接管理同义词集合的高效方式。每个同义词集合包含同义词规则,其中一组词在搜索中被视为等效。
创建同义词集示例
代码语言:json复制PUT _synonyms/my-synonyms-set
{
"synonyms_set": [
{
"id": "rule-1",
"synonyms": "hello, hi"
},
{
"synonyms": "bye, goodbye"
}
]
}
这创建了一个名为“my-synonyms-set”的集合,其中“hello”和“hi”被视为等效词,“bye”和“goodbye”也是如此。
为产品目录实现同义词创建
以下是构建同义词集并将其插入到Elasticsearch中的方法。根据LLM建议的同义词映射生成同义词规则。每个规则都有一个ID,对应于产品名称的slug格式,以及LLM计算的同义词列表。
代码语言:python代码运行次数:0运行复制import json
import logging
from elasticsearch import Elasticsearch
from slugify import slugify
es = Elasticsearch(
"http://localhost:9200",
api_key="your_api_key"
)
def mount_synonyms(results):
synonyms_set = [{"id": slugify(product), "synonyms": synonyms} for product, synonyms in results.items()]
try:
response = es.synonyms.put_synonym(id="products-synonyms-set", synonyms_set=synonyms_set)
logging.info(json.dumps(response.body, indent=4))
return response.body
except Exception as e:
logging.error(f"创建同义词时出错: {str(e)}")
return None
以下是创建同义词集的请求负载:
代码语言:json复制{
"synonyms_set":[
{
"id": "iphone-14-pro",
"synonyms": "iPhone, smartphone, mobile, handset"
},
{
"id": "macbook-pro-16-inch",
"synonyms": "MacBook, Laptop, Notebook, Computer"
},
{
"id": "samsung-galaxy-tab-s8",
"synonyms": "Tablet, Slate, Pad, Device"
},
{
"id": "garmin-forerunner-945",
"synonyms": "Forerunner, smartwatch, fitness watch, GPS watch"
},
{
"id": "bose-quietcomfort-35-headphones",
"synonyms": "Headphones, Earphones, Headset, Cans"
}
]
}
在集群中创建同义词集后,我们可以进入下一步,即使用定义的同义词集创建一个支持同义词的新索引。
完整的Python代码,包括LLM生成的同义词和Synonyms API定义的同义词集创建如下:
代码语言:python代码运行次数:0运行复制import json
import logging
from elasticsearch import Elasticsearch
from openai import OpenAI
from slugify import slugify
logging.basicConfig(level=logging.INFO)
client = OpenAI(api_key="your-key")
es = Elasticsearch("http://localhost:9200", api_key="your_api_key")
def call_gpt(prompt, model):
try:
logging.info("通过LLM生成同义词...")
response = client.chatpletions.create(
model=model,
messages=[{"role": "user", "content": prompt}],
temperature=0.7,
max_tokens=1000
)
content = response.choices[0].message.content.strip()
return content
except Exception as e:
logging.error(f"使用模型失败: {e}")
return None
def generate_synonyms(category, products):
synonyms = {}
for product in products:
prompt = (
f"你是产品同义词生成专家。根据提供的类别和产品名称生成同义词或相关术语。请遵循以下规则:\n"
f"1. **格式**:第一个词应为主要项目(产品名称的一部分,排除品牌),后跟最多3个用逗号分隔的同义词。\n"
f"2. **排除品牌**:同义词中不要包含品牌名称。\n"
f"3. **同义词数量**:每个产品最多生成3个同义词。\n\n"
f"类别为:**{category}**,产品为:**{product}**。只返回请求格式的同义词,不要附加解释。"
)
response = call_gpt(prompt, "gpt-4o")
synonyms[product] = response
return synonyms
def get_products(category):
query = {
"size": 50,
"_source": ["name"],
"query": {
"bool": {
"filter": [
{
"term": {
"category.keyword": category
}
}
]
}
}
}
response = es.search(index="products", body=query)
if response["hits"]["total"]["value"] > 0:
product_names = [hit["_source"]["name"] for hit in response["hits"]["hits"]]
return product_names
else:
return []
def mount_synonyms(results):
synonyms_set = [{"id": slugify(product), "synonyms": synonyms} for product, synonyms in results.items()]
try:
es_client = get_client_es()
response = es_client.synonyms.put_synonym(id="products-synonyms-set", synonyms_set=synonyms_set)
logging.info(json.dumps(response.body, indent=4))
return response.body
except Exception as e:
logging.error(f"更新同义词时出错: {str(e)}")
return None
if __name__ == '__main__':
category = "Electronics"
products = get_products("Electronics")
llm_synonyms = generate_synonyms(category, products)
mount_synonyms(llm_synonyms)
创建支持同义词的索引
将创建一个新索引,所有products
索引中的数据将被重新索引。这个索引将使用synonyms_filter
,应用之前创建的products-synonyms-set
。
以下是配置为使用同义词的索引映射:
代码语言:json复制PUT products_02
{
"settings": {
"analysis": {
"filter": {
"synonyms_filter": {
"type": "synonym",
"synonyms_set": "products-synonyms-set",
"updateable": true
}
},
"analyzer": {
"synonyms_analyzer": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"lowercase",
"synonyms_filter"
]
}
}
}
},
"mappings": {
"properties": {
"ID": {
"type": "long"
},
"category": {
"type": "keyword"
},
"name": {
"type": "text",
"analyzer": "standard",
"search_analyzer": "synonyms_analyzer"
}
}
}
}
重新索引products
索引
现在,我们将使用Reindex API将数据从products
索引迁移到包含同义词支持的新products_02
索引。以下代码在Kibana DevTools中执行:
POST _reindex
{
"source": {
"index": "products"
},
"dest": {
"index": "products_02"
}
}
迁移完成后,products_02
索引将被填充并准备好使用配置的同义词集进行搜索验证。
验证同义词搜索
让我们比较两个索引之间的搜索结果。我们将在两个索引上执行相同的查询,并验证是否使用同义词来检索结果。
在products
索引中搜索(不支持同义词)
我们将使用Kibana执行搜索并分析结果。在Analytics > Discovery菜单中,我们将创建一个数据视图以查看我们创建的索引数据。
在Discovery中,点击数据视图并定义名称和索引模式。对于“products”索引,我们将使用“products”模式。然后,我们将重复这个过程为“products_02”索引创建一个新的数据视图,使用“products_02”模式。
配置数据视图后,我们可以返回到Analytics > Discovery并开始验证。
在这里,选择DataView产品并搜索“tablet”一词后,我们没有得到结果,尽管我们知道有诸如“Kindle Paperwhite”和“Apple iPad Air”这样的产品。
在products_02
索引中搜索(支持同义词)
在支持同义词的“products_synonyms”数据视图中执行相同查询时,产品成功检索。这表明配置的同义词集正常工作,确保搜索词的不同变体返回预期结果。
我们可以通过直接在Kibana DevTools中运行相同的查询来达到相同的效果。只需使用Elasticsearch Search API搜索products_02索引:
结论
在Elasticsearch中实现同义词提高了产品目录搜索的准确性和覆盖范围。关键的差异在于使用了LLM,它自动且有上下文地生成同义词,消除了预定义列表的需求。模型分析了产品名称和类别,确保电子商务相关的同义词。
此外,Synonyms API简化了词典管理,允许动态修改同义词集。通过这种方法,搜索变得更加灵活,能够适应不同的用户查询模式。
这个过程可以通过新的数据和模型调整不断改进,确保更高效的搜索体验。
参考文献
本地运行Elasticsearch
.html
Synonyms API
.html
本文标签: 如何使用ES的同义词API自动化同义词生成和上传
版权声明:本文标题:如何使用ES的同义词API自动化同义词生成和上传 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/biancheng/1747554999a2707452.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论