目录
词干提取器标记过滤器(Stemmer token filters)
算法性词干提取器(Algorithmic stemmers)
本节解释了Elasticsearch中文本分析的基本概念。
分析器的结构
一个分析器,无论是内置的还是自定义的,只是一个包含三个较低级构建块的集合:字符过滤器、分词器和标记过滤器。
内置分析器将这些构建块预先打包成适用于不同语言和文本类型的分析器。Elasticsearch还公开了这些单独的构建块,以便可以将它们组合起来定义新的自定义分析器。
字符过滤器(Character filters)
字符过滤器接收原始文本作为字符流,并可以通过添加、删除或更改字符来转换该流。例如,字符过滤器可用于将印度-阿拉伯数字(٠١٢٣٤٥٦٧٨٩)转换为其阿拉伯-拉丁等效形式(0123456789),或者从字符流中删除HTML元素如<b>。
一个分析器可以包含零个或多个字符过滤器,这些过滤器按顺序应用。
分词器(Tokenizer)
分词器接收字符流,将其分解为单个标记(通常是单个单词),并输出一个标记流。例如,空格分词器在看到任何空格时将文本分解为标记。它会将文本 "Quick brown fox!"
转换为词项 [Quick, brown, fox!]
。
分词器还负责记录每个术语的顺序或位置,以及术语表示的原始单词的起始和结束字符偏移。
一个分析器必须有且只能有一个分词器。
标记过滤器(Token filters)
标记过滤器接收标记流,可以添加、删除或更改标记。例如,小写标记过滤器将所有标记转换为小写,停用词标记过滤器从标记流中删除常见词(停用词),同义词标记过滤器将同义词引入标记流。
标记过滤器不得更改每个标记的位置或字符偏移。
一个分析器可以包含零个或多个标记过滤器,这些过滤器按顺序应用。
索引和搜索分析
文本分析发生在两个时机:
-
索引时
当文档被索引时,对任何文本字段值进行分析。
-
搜索时
当在文本字段上运行全文搜索时,查询字符串(用户正在搜索的文本)被分析。
搜索时也被称为查询时间。
在每个时机使用的分析器或分析规则集分别称为索引分析器或搜索分析器。
索引和搜索分析器如何协同工作
在大多数情况下,应在索引时和搜索时使用相同的分析器。这确保了字段的值和查询字符串被转换成相同形式的标记。从而,这确保了在搜索时标记能够如预期般匹配。
Example
文档在文本字段中索引了以下值:
The QUICK brown foxes jumped over the dog!
该字段的索引分析器将该值转换为标记并对其进行规范化。在这种情况下,每个标记表示一个单词:
[ quick, brown, fox, jump, over, dog ]
该字段的索引分析器将该值转换为标记并对其进行规范化。在这种情况下,每个标记表示一个单词:
然后将这些标记进行索引。
之后,用户在同一文本字段中搜索:"Quick fox"
用户期望此搜索与先前索引的句子 "The QUICK brown foxes jumped over the dog!"
匹配。
然而,查询字符串中不包含文档原始文本中使用的确切单词:
- Quick 与 QUICK
- fox 与 foxes
为解决这个问题,使用相同的分析器对查询字符串进行分析。该分析器产生以下标记:
[ quick, fox ]
为执行搜索,Elasticsearch将这些查询字符串标记与文本字段中索引的标记进行比较。
Token | Query string | text field |
---|---|---|
quick | X | X |
brown | X | |
fox | X | X |
jump | X | |
over | X | |
dog | X |
由于字段值和查询字符串以相同的方式进行了分析,它们创建了相似的标记。标记 quick 和 fox 是精确匹配的。这意味着搜索与包含 "The QUICK brown foxes jumped over the dog!" 的文档匹配,正如用户所期望的那样。
何时使用不同的搜索分析器
虽然较为罕见,但有时在索引时和搜索时使用不同的分析器是有道理的。为了实现这一点,Elasticsearch允许您指定一个单独的搜索分析器。
通常情况下,只有在使用相同形式的标记为字段值和查询字符串创建意外或不相关的搜索匹配时,才应指定单独的搜索分析器。
Example
Elasticsearch 用于创建一个仅匹配以提供的前缀开头的单词的搜索引擎。例如,搜索 tr 应该返回 tram 或 trope,但永远不会返回 taxi 或 bat。
将一个包含这样一个单词的文档添加到搜索引擎的索引中:"Apple"
该字段的索引分析器将该值转换为标记并对其进行规范化。在这种情况下,每个标记表示单词的一个潜在前缀:
[ a, ap, app, appl, apple]
然后将这些标记进行索引。之后,用户在同一文本字段中搜索:"appli"
用户期望此搜索仅匹配以 appli 开头的单词,如 appliance 或 application。搜索不应该匹配 apple。
然而,如果使用索引分析器来分析此查询字符串,它将生成以下标记:
[ a, ap, app, appl, appli ]
当Elasticsearch将这些查询字符串标记与以 "apple" 为索引的标记进行比较时,发现了多个匹配项。
Token | appli | apple |
---|---|---|
a | X | X |
ap | X | X |
app | X | X |
appl | X | X |
appli | X |
这意味着搜索将错误地匹配 "apple"。而且,它将匹配任何以 a 开头的单词。
为解决这个问题,您可以为在文本字段上使用的查询字符串指定一个不同的搜索分析器。
在这种情况下,您可以指定一个搜索分析器,它产生一个单一的标记而不是一组前缀:
[ appli ]
这个查询字符串标记只会匹配以 "appli" 开头的单词的标记,这更符合用户的搜索期望。
词干提取(Stemming)
词干提取是将一个词减少到其根形式的过程。这确保在搜索过程中单词的变体能够匹配。
例如,walking 和 walked 可以被词干提取为相同的词根:walk。一旦被词干提取,任何一个词的出现都会在搜索中与另一个匹配。
词干提取是与语言相关的,但通常涉及删除单词的前缀和后缀。
在某些情况下,一个经过词干提取的单词的根形式可能不是一个真实的单词。例如,jumping
和 jumpiness
都可以被词干提取为 jumpi
。虽然 jumpi
不是一个真正的英语单词,但对于搜索来说并不重要;如果一个词的所有变体都被减少到相同的根形式,它们将正确匹配。
词干提取器标记过滤器(Stemmer token filters)
在Elasticsearch中,词干提取由词干提取器标记过滤器处理。这些标记过滤器可以根据它们词干提取的方式进行分类:
由于词干提取会改变标记,建议在索引和搜索分析中使用相同的词干提取器标记过滤器。
算法性词干提取器(Algorithmic stemmers)
算法性词干提取器对每个单词应用一系列规则,将其减少到其根形式。例如,英语的算法性词干提取器可能会从复数单词的末尾删除 -s 和 -es 后缀。
算法性词干提取器具有一些优点:
- 它们需要很少的设置,并且通常能够立即使用。
- 它们使用的内存较少。
- 它们通常比字典性词干提取器更快。
然而,大多数算法性词干提取器只会更改单词的现有文本。这意味着它们可能不适用于不包含其根形式的不规则单词,例如:
- be、are 和 am
- mouse 和 mice
- foot 和 feet
以下标记过滤器使用算法性词干提取:
- stemmer:为多种语言提供算法性词干提取,其中一些还具有额外的变体。
- kstem:用于英语的词干提取器,将算法性词干提取与内置词典结合在一起。
- porter_stem:我们推荐的英语算法性词干提取器。
- snowball:使用基于Snowball的词干提取规则,支持多种语言。
字典性词干提取器(Dictionary stemmers)
字典性词干提取器在提供的词典中查找单词,用词典中的词干替换未经过词干提取的单词变体。
理论上,字典性词干提取器非常适合于:
- 对不规则单词进行词干提取
- 区分拼写相似但在概念上不相关的单词,例如:
- organ 和 organization
- broker 和 broken
实际上,算法性词干提取器通常优于字典性词干提取器。这是因为字典性词干提取器具有以下缺点:
- 词典质量: 字典性词干提取器的性能取决于其词典的质量。为了良好地工作,这些词典必须包含大量的单词,定期更新,并随着语言趋势而变化。通常,在词典发布时,它可能是不完整的,其中一些条目可能已经过时。
- 大小和性能: 字典性词干提取器必须将其词典中的所有单词、前缀和后缀加载到内存中。这可能使用大量的RAM。低质量的词典也可能在前缀和后缀的删除方面效率较低,这可能显著减慢词干提取的过程。
您可以使用 hunspell 标记过滤器执行字典性词干提取。
如果可用,我们建议在使用 hunspell 标记过滤器之前尝试使用您语言的算法性词干提取器。
词干提取控制(Control stemming)
有时候,词干提取可能会产生拼写相似但在概念上无关的共享根词。例如,一个词干提取器可能将 skies 和 skiing 都减少到相同的根词:ski。
为了防止这种情况并更好地控制词干提取,您可以使用以下标记过滤器:
- stemmer_override: 允许您为词干提取指定特定标记的规则。
- keyword_marker: 将指定的标记标记为关键词。关键词标记的标记不会被后续的词干提取器处理。
- conditional: 可以用于将标记标记为关键词,类似于 keyword_marker 过滤器。
对于内置的语言分析器,您还可以使用 stem_exclusion 参数指定不进行词干提取的单词列表。
标记图(Token graphs)
当一个分词器将文本转换为标记流时,它还记录以下信息:
- 每个标记在流中的位置
- 位置长度(positionLength),即一个标记跨越的位置数量
利用这些信息,您可以为一个流创建一个有向无环图,称为标记图。在标记图中,每个位置表示一个节点。每个标记表示一条边或弧,指向下一个位置。
同义词(Synonyms)
一些标记过滤器可以向现有的标记流添加新的标记,比如同义词。这些同义词通常跨越与现有标记相同的位置。
在下面的图中,quick 和其同义词 fast 的位置都是 0。它们跨越相同的位置。
多位置标记(Multi-position tokens)
一些标记过滤器可以添加跨越多个位置的标记。这可能包括用于多词同义词的标记,例如将 "atm" 用作 "automatic teller machine" 的同义词。
然而,只有一些标记过滤器,称为图形标记过滤器,才能准确记录多位置标记的位置长度。这些过滤器包括:
- synonym_graph
- word_delimiter_graph
一些分词器,如 nori_tokenizer,也可以将复合标记准确分解为多位置标记。
在下面的图中,domain name system 和其同义词 dns 的位置都是 0。然而,dns 的位置长度为 3。图中的其他标记具有默认的位置长度为 1。
利用标记图进行搜索
在索引时,会忽略位置长度属性,并且不支持包含多位置标记的标记图。
然而,查询(例如 match 或 match_phrase 查询)可以利用这些图从单个查询字符串生成多个子查询。
Example
用户使用 match_phrase 查询运行了以下短语的搜索:
domain name system is fragile
在搜索分析期间,"dns",即 "domain name system" 的同义词,被添加到查询字符串的标记流中。"dns" 标记的位置长度为 3。
match_phrase 查询使用这个图生成以下短语的子查询:
dns is fragile
domain name system is fragile
这意味着查询将匹配包含 "dns is fragile" 或 "domain name system is fragile" 的文档。
无效的标记图(Invalid token graphs)
以下标记过滤器可以添加跨越多个位置的标记,但只记录默认位置长度为 1:
- synonym
- word_delimiter
这意味着这些过滤器将对包含这些标记的流生成无效的标记图。
在下面的图中,"dns" 是 "domain name system" 的多位置同义词。然而,"dns" 具有默认的位置长度值为 1,导致一个无效的图。
避免在搜索中使用无效的标记图。无效的图可能导致意外的搜索结果。