ElasticSearch 2 (25) - 语言处理系列之同义词
ElasticSearch 2 (25) - 语言处理系列之同义词
摘要
词干提取有助于通过简化屈折词到它们词根的形式来扩展搜索的范围,而同义词是通过关联概念和想法来扩展搜索范围的。或许没有文档能与查询 “English queen” 相匹配,但是包含 “British monarch” 的文档会很可能被认为是一个好的匹配。
用户搜索 “the US” 可能期望找到文档包含 United States、USA、U.S.A.、America 或 the States。但是,他们不希望看见结果里有关于 the states of matter 或 state machines 这样的内容。
示例给我们上了很好的一课,它展现了人区分不同概念的方式是怎样简单,但对于机器来说却那样麻烦。尝试为每个词都提供同义词,从而保证即使用关系较远的词也能找到文档,这是一个很自然的倾向。
但这是个错误,就如同我们偏向轻量或较小的词干提取程度而不是激进的提取方式,同义词应该仅在必要时使用。用户可以理解为什么他们的查询结果受查询条件的限制,但他们却不那么理解为什么他们的查询结果看上去总是随机的。
同义词可以被用来合并那些具有相同含义的词,比如:jump、leap 和 hop 或者 pamphlet、 leaflet 和 brochure。另外,它还可以使词更通用。比如,bird 可以作为 owl 或 pigeon 更通用的同义词,adult 可以作为 man 或 woman 的同义词。
同义词看似一个简单的概念,但是想让它们用得正确却十分微妙。本章中,我们会解释同义词的机制并且讨论它在使用上局限和陷阱。
小贴士
同义词是被用以扩展匹配文档的范围的。就和词干提取方式或部分匹配一样,同义词字段无法独立使用,而是需要将它和主字段查询联合使用,主字段里包含原始文本未经修改的形式。参见 多数字段(Most Fields) 了解在使用同义词时如何维护相关度的值。
版本
elasticsearch版本: elasticsearch-2.x
内容
同义词的使用(Using Synonyms)
同义词可以替换当前存在的标记,或者也可以通过使用同义词标记过滤器将其加入到标记流中:
PUT /my_index
{
"settings": {
"analysis": {
"filter": {
"my_synonym_filter": {
"type": "synonym", #1
"synonyms": [ #2
"british,english",
"queen,monarch"
]
}
},
"analyzer": {
"my_synonyms": {
"tokenizer": "standard",
"filter": [
"lowercase",
"my_synonym_filter" #3
]
}
}
}
}
}
#1 首先,我们定义了一个 synonym 类型的标记过滤器。
#2 我们会在 同义词格式化(Formatting Synonyms) 中讨论同义词的格式。
#3 使用 my_synonym_filter 过滤器创建一个自定义分析器。
小贴士
同义词可以通过内联参数
synonyms指定,或者通过一个存在于每个节点的同义词文件指定。同义词的文件路径参数为synonyms_path,它可以是 Elasticsearch 配置目录的相对路径,也可以是绝对路径。参见 更新停用词(Updating Stopwords) 可以找到刷新同义词列表的技术。
用 analyze API 测试我们的分析器:
GET /my_index/_analyze?analyzer=my_synonyms
Elizabeth is the English queen
Pos 1: (elizabeth)
Pos 2: (is)
Pos 3: (the)
Pos 4: (british,english) #1
Pos 5: (queen,monarch) #2
#1 #2 所有的同义词都与它们的原始词占据同一位置。
这个文档会与一下任何一个查询匹配:English queen、British queen、English monarch 或 British monarch。短语查询也能奏效,因为每个词项的位置都被保留了。
小贴士
同时在索引时和搜索时使用相同的同义词标记过滤器是多余的。如果我们在索引时将
English替换成了english和british,那么在搜索时只需要搜索其中的一个词项。另外,如果我们不在索引时使用同义词,那么在搜索时就需要将查询从English转换为english或british。是在搜索时还是在索引时中使用同义词是个难以取舍的选择,我们会在 扩展与收缩(Expand or contract) 中对这个问题的选择进行更多探索。
同义词的格式化(Formatting Synonyms)
同义词用逗号这种最简单的形式将值进行分隔:
"jump,leap,hop"
如果碰到任何词项,它会被列表里的所有同义词替换,例如:
Original terms: Replaced by:
────────────────────────────────
jump → (jump,leap,hop)
leap → (jump,leap,hop)
hop → (jump,leap,hop)
另外,使用 => 语法形式,可以指定(左边)供匹配的词项列表,以及(右边)列表里的一或多个替代:
"u s a,united states,united states of america => usa"
"g b,gb,great britain => britain,england,scotland,wales"
Original terms: Replaced by:
────────────────────────────────
u s a → (usa)
united states → (usa)
great britain → (britain,england,scotland,wales)
如果相同的同义词被指定了多个规则,它们会被合并,合并后是无序的。取而代之的是最长的匹配规则会获得胜利,以下面的规则为例:
"united states => usa",
"united states of america => usa"
如果规则冲突,Elasticsearch 可能会将 United States of America 拆解成 (usa),(of),(america),取而代之,因为最长的匹配会胜出,所以我们得到的最后结果是 (usa)。
扩展与收缩(Expand or contract)
在 格式化同义词(Formatting Synonyms) 中,我们已经看到可以通过简单扩展、简单收缩、或通用扩展来替换同义词,本小节中我们会看看如何在这些技术中作权衡。
小贴士
本小节只处理单个词的同义词,多词同义词会增加问题的复杂度,会在 多词同义词与短语查询(Multiword Synonyms and Phrase Queries) 中进行讨论。
简单扩展(Simple Expansion)
在简单扩展中,任何同义词都会被扩展替换成同义词列表里的所有词:
"jump,hop,leap"
扩展可以被应用于索引时或查询时。每种方式都有它的优势(⬆)和劣势(⬇)。何时使用何种方式对性能和灵活性产生的影响。
(原)
| Index time | Query time
-------------------------------------------------------------------------------------
Index size | ⬇︎ Bigger index because | ⬆︎ Normal.
| all synonyms must be indexed. |
-------------------------------------------------------------------------------------
Relevance | ⬇︎ All synonyms will have the same | ⬆︎ The IDF for each
| IDF (see What Is Relevance?), | synonym will be correct.
| meaning that more commonly used |
| words will have the same weight |
| as less commonly used words. |
-------------------------------------------------------------------------------------
Performance | ⬆︎ A query needs to find only the | ⬇︎ A query for a single
| single term specified | term is rewritten to
| in the query string. | look up all synonyms,
| | which decreases performance.
-------------------------------------------------------------------------------------
Flexibility | ⬇︎ The synonym rules can’t be | ⬆︎ Synonym rules can be
| changed for existing documents. | updated without reindexing
| For the new rules to have effect, | documents.
| existing documents have to be |
| reindexed. |
-------------------------------------------------------------------------------------
(译)
| 索引时 | 查询时
-------------------------------------------------------------------------------------
索引大小 | ⬇︎ 索引占用空间更大,因为所有同义词 |
| 都需要被索引 | ⬆︎ 正常
-------------------------------------------------------------------------------------
相关性 | ⬇︎ 所有的同义词都有相同的IDF (参见 | ⬆︎ 每个索引的 IDF 是正确的
| 什么是相关性?)这表示较常用词与 |
| 次常用词具有相同的权重 |
-------------------------------------------------------------------------------------
性能 | ⬆︎ 查询只需要对查询字符串中的单个指定 | ⬇︎ 单个词的查询被重写为查找
| 词项进行查找 | 所有的同义词这会降低搜索性能
| |
-------------------------------------------------------------------------------------
灵活性 | ⬇︎ 同义词规则无法更改现有文档,要想使 | ⬆︎ 无需重建索引就能更新同义
| 用规则生效就必须对现有文档重建索引 | 词规则
| |
-------------------------------------------------------------------------------------
简单收缩(Simple Contraction)
简单搜索是将左边的一组同义词映射到右边的单个值:
"leap,hop => jump"
它需要同时应用于索引时和查询时,来确保查询词项能与索引中已有的同一值映射。
这种方式与简单扩展方式相比既有优势也有不足:
索引大小
⬆︎ 索引大小正常,因为只有单个词项需要被索引。
相关性
⬇︎ 所有词项的 IDF 都是相同的,所以我们无法区分较常用词和次常用词。
性能
⬆︎ 查询需要在索引中找到唯一的单个词项。
灵活性
⬆︎ 新同义词可以被加到规则左边并在查询时应用。例如,假设我们想要将单词
bound加入之前指定的规则,以下这个规则可以用来查询已有或新增的包含bound的文档:"leap,hop,bound => jump"
但我们也可以扩展这个效果,将 已有 包含
bound的文档考虑在内,规则如下:"leap,hop,bound => jump,bound"
当我们重建索引后,我们可以回撤到前一个规则,从而在对单个词项进行查询时,获取性能收益。
类型扩展(Genre Expansion)
类型扩展与简单收缩或简单扩展大不相同。它不是平等对待所有的同义词,而是扩展了词项的含义,使它变得更加抽象通用。用以下规则来举例:
"cat => cat,pet",
"kitten => kitten,cat,pet",
"dog => dog,pet"
"puppy => puppy,dog,pet"
在索引时应用类型扩展:
- 查询
kitten可能只会找到关于 kittens (小猫)的文档。 - 查询
cat可能会找到关于 kittens 和 cats (小猫和猫)的文档。 - 查询
pet可能会找到关于 kittens、cats、puppies、dogs 或 pets (小猫、猫、小狗、狗 或 宠物)的文档。
另外,如果在查询时应用类型扩展,查询 kitten 会将结果扩展至所有提及 kittens、cats 或 pets 的文档。
我们还有个一箭双雕的做法,就是在索引时应用扩展来确保索引里存在该类型,然后在查询时,我们既可以不应用同义词(这样查询 kitten 就只会返回仅关于 kittens 小猫的文档)或者也可以选择应用同义词来匹配 kittens、cats 和 pets(包括多种犬类)。
有了以上示例中的规则,kitten 的 IDF 会是正确的,尽管 cat 和 pet 的 IDF 都被认为弱化了。尽管如此,它还是能满足我们的要求,一个类型扩展查询 kitten OR cat OR pet 会将 kitten 的相关文档排在最前,随后是 cat 的相关文档,最后是 pet 出现在最后。
同义词及其分析链(Synonyms and The Analysis Chain)
在 格式化同义词(Formatting Synonyms) 这一小节的例子中,用 u s a 作为同义词。为什么我们要使用它而不是使用 U.S.A. 呢?原因是同义词标记过滤器只能看见它之前的标记过滤器或标记器的输出。
假设我们有一个分析器,它由 standard 标记器,lowercase 标记过滤器,以及一个 synonym 标记过滤器依次组成。那么文本 U.S.A. 的分析过程会是如下这样:
original string → "U.S.A."
standard tokenizer → (U),(S),(A)
lowercase token filter → (u),(s),(a)
synonym token filter → (usa)
如果我们指定 U.S.A. 作为同义词,它不会与任何值匹配,因为当 my_synonym_filter 看见词项的时候,英文的句号已经被移除了,所有的字母都变成了小写形式。
这是需要考虑的重点。如果我们想将同义词与词干提取组合起来,使jumps、jumped、jump、leaps、leaped 和 leap 都以同一个词 jump 来索引,怎么办?我们可以在提取器之前设置同义词过滤器,并列出所有的屈折词:
"jumps,jumped,leap,leaps,leaped => jump"
但是更简洁的方式是在提取器之后设置同义词过滤器,然后列出提取器输出的所有词根:
"leap => jump"
大小写敏感的同义词(Case-Sensitive Synonyms)
通常情况下,同义词过滤器被置于小写标记过滤器之后,这样所有的同义词都可以转换成小写形式,但这在有些时候会带来奇怪的词项合并。例如,CAT scan 和 cat 有着很大不同,PET(positron emmision tomography,正电子放射断层造影术)和 pet 同样如此。正因为这样,姓 Little 也与形容词 little 有区别(尽管如果形容词在句首,首字母也会被大写)。
如果我们有的应用场景需要区分词义,我们可以将同义词过滤器置于小写过滤器之前,当然这样做也意味着需要在同义词规则中列出所有我们期望匹配的大小写变化形式(例如,Little、LITTLE、little)
与上面不同,我们可以有两个同义词过滤器:一个用来捕获大小写敏感的同义词,另一个用来处理所有大小写不敏感的同义词。例如,大小写敏感规则如下:
"CAT,CAT scan => cat_scan"
"PET,PET scan => pet_scan"
"Johnny Little,J Little => johnny_little"
"Johnny Small,J Small => johnny_small"
而大小写不敏感的规则如下:
"cat => cat,pet"
"dog => dog,pet"
"cat scan,cat_scan scan => cat_scan"
"pet scan,pet_scan scan => pet_scan"
"little,small"
大小写敏感的规则会有 CAT scan 但只会匹配 CAT scan 里的 CAT,正因如此,在大小写不敏感列表中,我们有 cat_scan scan 这样看上去很奇怪的规则用来处理错误替换。
小贴士
我们可以看见它发展得如此之快以至于变得无比复杂。一如往常,
analyzeAPI 总能成为我们检查分析器配置正确性的良师益友。参见 测试分析器(Testing Analyzers) 。
多词同义词与短语查询(Multiword Synonyms and Phrase Queries)
目前为止同义词看起来比较明确,不幸的是,这却恰恰是错误的开始。为了能使短语查询正确工作,Elasticsearch 需要知道每个词项在原始文本的位置,多词同义词会大量使用词项位置信息,特别是当注入同义词长度不同的时候。
为了方便展示,我们会创建同义词标记过滤器并使用规则:
"usa,united states,u s a,united states of america"
PUT /my_index
{
"settings": {
"analysis": {
"filter": {
"my_synonym_filter": {
"type": "synonym",
"synonyms": [
"usa,united states,u s a,united states of america"
]
}
},
"analyzer": {
"my_synonyms": {
"tokenizer": "standard",
"filter": [
"lowercase",
"my_synonym_filter"
]
}
}
}
}
}
GET /my_index/_analyze?analyzer=my_synonyms&text=
The United States is wealthy
分析请求输出的标记结果如下:
Pos 1: (the)
Pos 2: (usa,united,u,united)
Pos 3: (states,s,states)
Pos 4: (is,a,of)
Pos 5: (wealthy,america)
如果我们要用以上同义词对文档进行分析索引,如果不使用同义词并执行短语查询,可能会得到令人惊讶的结果。以下短语无法匹配:
- The usa is wealthy
- The united states of america is wealthy
- The U.S.A. is wealthy
但是这些短语可以匹配:
- United states is wealthy
- Usa states of wealthy
- The U.S. of wealthy
- U.S. is america
如果我们在查询时使用同义词,我们会看到更加奇怪搞笑的结果。查看 validate-query 请求的输出:
GET /my_index/_validate/query?explain
{
"query": {
"match_phrase": {
"text": {
"query": "usa is wealthy",
"analyzer": "my_synonyms"
}
}
}
}
解释如下:
"(usa united u united) (is states s states) (wealthy a of) america"
这会匹配 u is of america 包含短语的文档,但是无法匹配那些不包含 america 的文档。
小贴士
多词同义词同样影响高亮的功能。查询
USA会返回高亮片段:“The United States is wealthy”。
为短语查询使用简单收缩(Use Simple Contraction for Phrase Queries)
避免这种混乱的方式可以通过以下方式解决:应用简单收缩用单个词项代表所有的同义词,然后在查询时使用相同的同义词标记过滤器:
PUT /my_index
{
"settings": {
"analysis": {
"filter": {
"my_synonym_filter": {
"type": "synonym",
"synonyms": [
"united states,u s a,united states of america=>usa"
]
}
},
"analyzer": {
"my_synonyms": {
"tokenizer": "standard",
"filter": [
"lowercase",
"my_synonym_filter"
]
}
}
}
}
}
GET /my_index/_analyze?analyzer=my_synonyms
The United States is wealthy
上面分析请求的结果看上去正常许多:
Pos 1: (the)
Pos 2: (usa)
Pos 3: (is)
Pos 5: (wealthy)
再次执行之前的 validate-query 请求,解释结果也变得简单、合理:
"usa is wealthy"
这种方式的不好之处在于,将 united states of america 缩减成单个词项 usa,让我们无法使用相同字段查找词语 united 或 states。我们需要使用独立的字段以及不同的分析链达到这个目的。
同义词和 query_string 查询(Synonyms and the query_string Query)
前面以及尝试避免讨论 query_string 查询,因为我们并不推荐使用它。在 "更复杂的查询(More-Complicated Queries)" 中,因为 query_string 查询支持一种简单短小的搜索语法,它会经常导致令人意外的结果甚至语法错误。
这个查询有一个陷阱与多词同义词相关。为了支持它的搜索语法,它需要解析查询字符串从而识别特殊的操作符,如 AND、OR、+、-、field: 等等。(参见 完整的 query_string 语法 了解更多信息)。
作为解析过程的一部分,它在空格处对查询字符串进行分解,然后将每个词分别传入对应的分析器,这意味着同义词分析器永远都不会收到多词同义词。它无法看到 United States 作为单个字符串出现,分析器会分别收到 United 和 States 这两个词。
幸运的是,可靠的 match 查询不支持这种语法,多词同义词会以它们自身的完整形式被传入分析器。
符号的同义词(Symbol Synonyms)
本章的最后部分会讨论符号的同义词,这与我们前面讨论的同义词不同。符号同义词是字符串的别名形式用以表示符号,它们通常会在标记化阶段被移除。
尽管大多数标点符号对于全文搜索不是那么重要,像表情这样的字符组合却很有意义,它甚至可能改变文本的意思。比较以下句子:
- I am thrilled to be at work on Sunday.
- I am thrilled to be at work on Sunday
ElasticSearch 2 (25) - 语言处理系列之同义词的更多相关文章
- ElasticSearch 2 (26) - 语言处理系列之打字或拼写错误
ElasticSearch 2 (26) - 语言处理系列之打字或拼写错误 摘要 我们喜欢在对结构化数据(如:日期和价格)做查询时,结果只返回那些能精确匹配的文档.但是,好的全文搜索不应该有这样的限制 ...
- ElasticSearch 2 (22) - 语言处理系列之标记规范化
ElasticSearch 2 (22) - 语言处理系列之标记规范化 摘要 将文本拆解成标记只是工作的一半.为了使这些标记更容易被搜索到,它们需要经过一个规范化的处理过程,以移除相同单词间不重要的差 ...
- ElasticSearch 2 (20) - 语言处理系列之如何开始
ElasticSearch 2 (20) - 语言处理系列之如何开始 摘要 Elasticsearch 配备了一组语言分析器,为世界上大多数常见的语言提供良好的现成基础支持. 阿拉伯语.亚美尼亚语,巴 ...
- ElasticSearch 2 (19) - 语言处理系列之故事开始
ElasticSearch 2 (19) - 语言处理系列之故事开始 摘要 全文搜索是精度(尽可能少的返回不相关文档)和召回(尽可能多的返回相关文档)的战场.尽管只精确匹配用户查询的词肯定会是精确的, ...
- ElasticSearch 2 (24) - 语言处理系列之停用词:性能与精度
ElasticSearch 2 (24) - 语言处理系列之停用词:性能与精度 摘要 在信息检索早期,磁盘和内存相较我们今天的使用只是很小的一部分.将索引空间保持在一个较小的水平是至关重要的,节省每个 ...
- ElasticSearch 2 (23) - 语言处理系列之词根提取
ElasticSearch 2 (23) - 语言处理系列之词根提取 摘要 世界上大多数语言都是屈折变化的,意思是词语可以通过变形来表达不同的含义: 数(Number): fox, foxes 时态( ...
- ElasticSearch 2 (21) - 语言处理系列之单词识别
ElasticSearch 2 (21) - 语言处理系列之单词识别 摘要 一个英语单词相对容易识别:因为英语单词是被空格或(某些)标点符号隔开的.但在英语中也有反例:you're 这个词是一个单词还 ...
- ElasticSearch 2 (18) - 深入搜索系列之控制相关度
ElasticSearch 2 (18) - 深入搜索系列之控制相关度 摘要 处理结构化数据(比如:时间.数字.字符串.枚举)的数据库只需要检查一个文档(或行,在关系数据库)是否与查询匹配. 布尔是/ ...
- ElasticSearch 2 (14) - 深入搜索系列之全文搜索
ElasticSearch 2 (14) - 深入搜索系列之全文搜索 摘要 在看过结构化搜索之后,我们看看怎样在全文字段中查找相关度最高的文档. 全文搜索两个最重要的方面是: 相关(relevance ...
随机推荐
- 阿里开源 iOS 协程开发框架 coobjc!--异步编程的问题与解决方案
阿里妹导读:刚刚,阿里巴巴正式对外开源了基于 Apache 2.0 协议的协程开发框架 coobjc,开发者们可以在 Github 上自主下载.coobjc是为iOS平台打造的开源协程开发框架,支持O ...
- sql 一个表的字段更新至另一个字段的方法
update Lc_Taxs set TaxMember = convert(int,Lc_Taxs2.TaxNo) from Lc_Taxs a,(select * from Lc_Taxs ) ...
- 如何高效的通过BP算法来训练CNN
< Neural Networks Tricks of the Trade.2nd>这本书是收录了1998-2012年在NN上面的一些技巧.原理.算法性文章,对于初学者或者是正在学习NN的 ...
- Features + Git + Drush,打造你的Drupal开发与维护标准工作流
还在为如何将本地的开发工作如何部署到生产环境而皱眉头?本文以实战历程教你如何一步步将你的工作成果从开发环境部署到生产环境. 如题所示,需要用到Features, Git, Drush:如果你还不知道他 ...
- Linux下端口被占用确认
有时候关闭软件后,后台进程死掉,导致端口被占用.下面以JBoss端口8083被占用为例,列出详细解决过程. 解决方法: 1.查找被占用的端口 netstat -tln netstat -tln | g ...
- HBase启动时报错:/bin/java: No such file or directory6/bin/../bin/hbase: line 412: /usr/local/jdk1.8.0_152/bin/java
今天在启动HBase时发现如下错误:/bin/java: No such file or directory6/bin/../bin/hbase: line 412: /usr/local/jdk1. ...
- [Lydsy1805月赛]口算训练 BZOJ5358
分析: 没想到这道题还能二分查找... 这题主席树的话,裸的很显然...我们将每一个数分解质因数,之后建一个可持久化权值线段树维护[L,R]区间内的每一种质因子的个数,分解质因数的话,可以选择用线筛, ...
- maven使用出现的错误
修改mvn archetype:create 改成mvn archetype:generate 刚开始学习用Maven, 装好了以后生成一个新的project mvnarchetype:genera ...
- test temp
http://img3.cache.netease.com/love/cssjs/20026/script/page/common.jshttp://img3.cache.netease.com/lo ...
- 20155210 EXP6 信息搜集与漏洞扫描
20155210 EXP6 信息搜集与漏洞扫描 信息搜集 外围信息搜集 通过DNS和IP挖掘目标网站的信息 whois 域名注册信息查询 我们通过输入whois qq.com可查询到3R注册信息,包括 ...
- ElasticSearch 2 (26) - 语言处理系列之打字或拼写错误