作者:来自 Elastic Jhon Guzmán
了解如何在 Kibana 中使用 Synonyms UI 创建同义词集并将其分配给索引。
刚接触 Elasticsearch?加入我们的 Elasticsearch 入门网络研讨会吧。你也可以立即开始免费的云试用,或在自己的机器上体验 Elastic。
Elasticsearch 9.1 引入了一个 UI,使同义词集的创建、维护以及将同义词分配给索引变得更简单。它基于 Synonyms API,该 API 在 8.10.0 版本中引入。
在 Elasticsearch 中,同义词是用于在文档分析和查询时将不同术语视为等价的规则。它们对于处理语言差异非常有用,例如缩写(“AI” ↔ “artificial intelligence”)、不同拼写(“Wi-Fi” ↔ “wifi”)或产品名称(“dress shirt” ↔ “formal shirt”),这样用户在搜索时可以看到包含所有查询词变体的结果。
在这篇博客中,我们将介绍在 Elasticsearch 中配置同义词的方法,展示如何使用 Synonyms UI 创建同义词集,并解释等价同义词和显式同义词之间的区别。
索引时同义词 vs 搜索时同义词
在 Elasticsearch 中有两种配置同义词的方式:在建立索引时或在查询时。每种方式都有不同的影响。
来看一下它们的主要区别:
- 索引时同义词:在为文档建立索引时创建同义词,会展开 tokens 并将它们存储在倒排索引中。这种方式:
-
增加索引大小。
-
影响索引中的词元统计,因为这些同义词也会被 BM25 算法考虑,从而影响最终的文档评分。
-
- 搜索时同义词:在查询时计算同义词,会展开搜索 tokens 并与索引中的 tokens 进行比较。这种方式:
-
不影响索引。
-
会略微增加查询响应时间,因为每次运行查询时都需要计算同义词。
-
如果你想了解这两种方法的更多信息,请参阅《The same, but different: Boosting the power of Elasticsearch with synonyms》。
总体来说,选择哪种方法取决于使用场景。不过,在大多数情况下,最好使用搜索时同义词,因此本文将采用这种方式。此外,同义词集(即可以视为等价的一组词)只能在查询过程中应用。
使用 Synonyms UI 创建同义词集
同义词集是一组作为逻辑容器的词组,用于定义哪些术语应被视为同义词的规则。在每个集合中,你可以添加单向或双向的词列表和相关表达式。最棒的是,只需点击几下,你就能轻松将它们添加到任意索引中。
现在,让我们使用 Synonyms UI 为与 AI 相关的文档创建一个同义词集。你可以在 Kibana 的侧边菜单中访问此工具,路径为:Elasticsearch > Relevance > Synonyms。
当你点击 Synonyms 后,会看到一个 “Get Started ” 界面。点击 “Create”:
我们将该集合命名为 ai-synonyms。在下一个界面中,我们将定义规则:
规则可以是等效的(双向)或显式的(单向)。我们将在下一节中进一步了解这些规则。
等效同义词(双向)
在 Elasticsearch 中,双向或等效同义词规则意味着在文档集合中这些词是可互换的,例如电商网站中的 iphone/smart phone。
让我们创建一个包含四条规则的等价同义词集:
`
1. chatbot ↔ artificial intelligence
2. self-driving car ↔ autonomous vehicle
3. llm ↔ large language model
4. ai ↔ artificial intelligence
`AI写代码
你可以开始添加词语,并使用逗号、回车或 shift 将词插入列表:
在完成上面的界面后,我们点击 Save:
现在,让我们创建将使用该集合的索引。进入 Dev Tools 并运行下面的脚本。这将创建一个包含两个字段的索引:title 和 title.synonyms,这样我们就可以轻松看到使用同义词搜索与不使用同义词搜索的区别。
`
1. PUT ai_articles
2. {
3. "settings": {
4. "analysis": {
5. "filter": {
6. "ecom_syns": {
7. "type": "synonym",
8. "synonyms_set": "ai-synonyms",
9. "updateable": true
10. }
11. },
12. "analyzer": {
13. "my_search_analyzer": {
14. "tokenizer": "standard",
15. "filter": ["lowercase", "ecom_syns"]
16. }
17. }
18. }
19. },
20. "mappings": {
21. "properties": {
22. "title": {
23. "type": "text",
24. "analyzer": "standard",
25. "fields": {
26. "synonyms": {
27. "type": "text",
28. "search_analyzer": "my_search_analyzer"
29. }
30. }
31. }
32. }
33. }
34. }
`AI写代码
接下来,你需要将这些文档建立索引:
`
1. POST _bulk
2. { "index": { "_index": "ai_articles", "_id": "1" } }
3. { "title": "Artificial Intelligence in Healthcare" }
4. { "index": { "_index": "ai_articles", "_id": "2" } }
5. { "title": "Chatbot for Customer Support" }
6. { "index": { "_index": "ai_articles", "_id": "3" } }
7. { "title": "Self-Driving Car Safety Guide" }
8. { "index": { "_index": "ai_articles", "_id": "4" } }
9. { "title": "Autonomous Vehicle Safety Guide" }
10. { "index": { "_index": "ai_articles", "_id": "5" } }
11. { "title": "Large Language Model Training Basics" }
12. { "index": { "_index": "ai_articles", "_id": "6" } }
13. { "title": "LLM Inference Optimization" }
14. { "index": { "_index": "ai_articles", "_id": "7" } }
15. { "title": "AI: Appreciative Inquiry in Organizational Change" }
`AI写代码
最后,运行此查询:
`
1. GET ai_articles/_search
2. {
3. "query": {
4. "match": {
5. "title": "llm"
6. }
7. }
8. }
`AI写代码
你会看到,我们只获得了精确匹配的结果,而标题为 Large Language Model Training Basics 的文章没有被包含。
现在,让我们使用同义词字段运行查询:
`
1. GET ai_articles/_search
2. {
3. "query": {
4. "match": {
5. "title.synonyms": "llm"
6. }
7. }
8. }
`AI写代码
现在我们得到了包含 LLM 和 large language model 的文档:
由于这是等价或双向规则,如果我们现在搜索 “large language model”,也会得到相同的结果:
`
1. GET ai_articles/_search
2. {
3. "query": {
4. "match": {
5. "title.synonyms": "large language model"
6. }
7. }
8. }
`AI写代码
显式同义词(单向)
与等价同义词不同,显式同义词只单向生效:从源词到目标词,但反向不成立。
目前,由于我们所有的规则都是等价的,当我们运行下面的搜索时:
`
1. GET ai_articles/_search
2. {
3. "query": {
4. "match": {
5. "title.synonyms": "artificial intelligence"
6. }
7. }
8. }
`AI写代码
我们得到了文章 #7,即使它与 “Artificial Intelligence” 无关,因为两个术语(AI 和 Artificial Intelligence)被认为是等价的。
`
1. {
2. "took": 1,
3. "timed_out": false,
4. "_shards": {
5. "total": 1,
6. "successful": 1,
7. "skipped": 0,
8. "failed": 0
9. },
10. "hits": {
11. "total": {
12. "value": 3,
13. "relation": "eq"
14. },
15. "max_score": 3.4859602,
16. "hits": [
17. {
18. "_index": "ai_articles",
19. "_id": "1",
20. "_score": 3.4859602,
21. "_source": {
22. "title": "Artificial Intelligence in Healthcare"
23. }
24. },
25. {
26. "_index": "ai_articles",
27. "_id": "2",
28. "_score": 1.7429801,
29. "_source": {
30. "title": "Chatbot for Customer Support"
31. }
32. },
33. {
34. "_index": "ai_articles",
35. "_id": "7",
36. "_score": 1.4617822,
37. "_source": {
38. "title": "AI: Appreciative Inquiry in Organizational Change"
39. }
40. }
41. ]
42. }
43. }
`AI写代码
如果我们创建一个单向规则 ai => artificial intelligence,当我们搜索 “ai” 时,Elasticsearch 会将 “ai” 替换为 “artificial intelligence”,因此此次搜索:
请注意,一个规则集可以同时包含显式同义词和等价同义词规则。
`
1. GET ai_articles/_search
2. {
3. "query": {
4. "match": {
5. "title.synonyms": "ai"
6. }
7. }
8. }
`AI写代码
从上面的结果中,我们可以看到 _id 为 7 的文档也被搜索到了。我们需要删除之前定义的 ai 等效同义词:
我们再次搜索:
`
1. GET ai_articles/_search
2. {
3. "query": {
4. "match": {
5. "title.synonyms": "ai"
6. }
7. }
8. }
`AI写代码
即使有其他文档包含 “ai”,也只会返回包含 “artificial intelligence” 的结果。
你可以使用 API _analyze 来查看它是如何工作的:
`
1. POST ai_articles/_analyze
2. {
3. "analyzer": "my_search_analyzer",
4. "text": "AI"
5. }
`AI写代码
你可以清楚地看到,我们只得到两个 tokens,而不会有仅包含 “ai” 的结果:
`
1. {
2. "tokens": [
3. {
4. "token": "artificial",
5. "start_offset": 0,
6. "end_offset": 2,
7. "type": "SYNONYM",
8. "position": 0
9. },
10. {
11. "token": "intelligence",
12. "start_offset": 0,
13. "end_offset": 2,
14. "type": "SYNONYM",
15. "position": 1
16. }
17. ]
18. }
`AI写代码
为了避免丢失同时包含 “ai” 的文档,我们可以调整配置,使该术语不仅被替换,还被扩展:
我们只需在 Synonyms UI 中这样定义规则:ai => artificial intelligence, ai。
Elasticsearch 会立即在索引中显示此更改,因此使用 “ai” 的相同查询现在会返回更多结果:
`
1. GET ai_articles/_search
2. {
3. "query": {
4. "match": {
5. "title.synonyms": "ai"
6. }
7. }
8. }
`AI写代码
响应:
结论
同义词在搜索中至关重要,因为它们涵盖了用户可能使用的同一个词的不同变体。Elasticsearch 支持等价同义词和显式同义词,以更好地捕捉用户意图。等效同义词在词语之间建立等效关系,而显式同义词则定义一个词作为另一个词的同义词,但反向不成立。
通过在 Kibana 中使用 Synonym UI,我们可以执行以前只能通过 synonyms API 完成的维护任务。