第五章 Elasticsearch Text analysis 文本分析
摘要
文本分析是将非结构化文本(例如电子邮件的正文或产品说明)转换为针对搜索优化的结构化格式的过程。
当对text
字段建立索引或搜索时,Elasticsearch 会执行文本分析。
但是,如果您使用text字段或文本搜索未返回预期的结果,则配置文本分析通常会有所帮助。如果您正在使用Elasticsearch执行以下操作,则还应该研究分析配置:
- 建立一个搜索引擎
- 非结构化数据
- 优化搜索特定语言
- 进行词典或语言研究
概述
文本分析使Elasticsearch能够执行全文搜索,其中搜索返回所有相关结果,而不仅仅是精确匹配。
如果您进行搜索Quick fox jumps
,则可能需要包含的文档:A quick brown fox jumps over the lazy dog
,还可能需要包含诸如fast fox
或的相关单词的文档foxes leap
。
Tokenization 标记化
分析使得标记化的全文搜索成为可能。将文本分解成为较小的块,成为标记(token
)。在英语语义下,通常为单个单词。
如果您将词组索引the quick brown fox jumps
为单个单词,并且用户搜索的时quick fox
,则不会将其视为匹配项。但是,如果您对短语进行标记,并分别索引单个单词,则可以单独查询字符串中的术语,这意味着他们可以通过搜索进行匹配quick fox
,fox brown
或其他变化。
Normalization 正常化
tokenization 可以匹配单个术语,但每个标记仍是机械的匹配,这就意味着:
1. quick
和Quick
不会匹配,即使是你希望它们之间会相互匹配。
2. fox
和foxes
拥有相同的词根,但也不会相互匹配
3. 同义词之间也不会相互匹配
为了解决这些问题,文本分析可以将这些标记标准化为标准格式。这样,您就可以匹配与搜索字词不完全相同但足够相似但仍具有相关性的标记。
为了保证搜索的准确性,您可以把搜索时的文本分析和索引里的文本分析设置为一致。
Customize text analysis 自定义文本分析
文本分析由分析器执行,它是控制整个过程的一组规则。
Elasticsearch包含一个默认的分析器,称为 标准分析器,它对于开箱即用的大多数用例都适用。
如果要定制搜索体验,则可以选择其他 内置分析仪,甚至可以 配置自定义分析仪。定制分析器使您可以控制分析过程的每个步骤,包括:
- 标记化 之前 对文本的更改
- 文本如何转换为令牌
- 在索引或搜索之前对令牌进行规范化更改
Text analysis concepts 文本分析概念
解析分析器
一个分析器,无论是内置的还是自定义的,都是一个包,包含三个最基本的模块:character filters, tokenizers, and token filters
内置的分析器将这些构件预先打包为适合不同语言和文本类型的分析器。Elasticsearch还公开了各个构建基块,以便可以将它们组合以定义新的custom分析器。
character filters 字符过滤器
一个character filters
接受一个原始的文本,作为一个字符串的流,并且可以添加,移除,改变。一个分析器,可能会拥有零个或者多个character filters
,按照一定的顺序使用。
tokenizer 分词器
一个tokenizer
接受一个字符流,将他们拆分成独立的标记,并输出。
分词器还负责记录每个术语的顺序或位置以及该术语代表的原始单词的开始和结束字符偏移量。
分析器必须仅具有一个标记器。
token filters 标记过滤器
一个token filters
接受一个标记流,可能会添加、移除、改变一个标记。但是不允许改变,标记在原文本中的位置或者字符的偏移量。分析器可能具有零个或多个按顺序应用的令牌过滤器。
索引和分析
文本分析会出现在两种情况下:
- 添加文档(index time),text字段会被分析
- 全文搜索, 对text字段进行全文搜索时,会对匹配项进行文本分析
每次使用的分析器或一组分析规则分别称为索引分析器或搜索分析器。
如何一起使用索引和搜索分析
在默认情况下,或是说,在大多数情况下,会使用相同的分析器。确保搜索和索引的一致性。
示例
The QUICK brown foxes jumped over the dog!
分析成,[ quick, brown, fox, jump, over, dog ]
可以使用下面的API,来获取文本分析结果
GET /_analyze
{
"analyzer" : "standard",
"text" : ["this is a test", "the second text"]
}
Stemming 获取单词的词根
Stemming 就是将原单词,还原成词根的形式。这样就保证在搜索过程中,匹配单词的变体。在某些情况下,词干的词根形式可能不是真实的词,但这不影响搜索。如果将单词的所有变体都简化成为相同的词根形式,则他们将会正确的匹配。
Stemmer Token filter 词干标记过滤器
在Elasticsearch 中,抽取词干是由stemmer token filter完成的,这些过滤器可以基于一定的方法完成。
- 算法(Algorithmic stemmers),通过一定的规则抽取
- 字典(dictionary stemmers),通过字典查找
由于词干会改变标记,因此建议在索引和搜索期间使用相同的词干令牌过滤器
Algorithmic stemmers 算法提取词干
这种词干抽取器,为每个词提供一系列规则,将其简化为词根形式。
优点:
- 需要很少的设置,开箱即用
- 使用较小的内存
- 比字典的方式要快
但是,大多数算法词干仅会更改单词的现有文本。这意味着它们可能不适用于不包含其词根形式的不规则单词。
以下是常用的算法:
stemmer
,它提供了几种语言的算法词干,其中一些带有其他变体。kstem
,是英语的词干分析器,它将算法词干与内置词典结合在一起。porter_stem
,是我们推荐的英语算法提取器。snowball
,它对几种语言使用 基于Snowball的词干规则。
Dictionary stemmers 字典提取词干
查找提供的字典中的词,使用字典中的词干。
- 阻止不规则单词
- 辨别拼写相似但概念上不相关的单词
在实践中,算法词干分析器通常优于字典词干分析器。这是因为词干分析器具有以下缺点:
- 词典质量,词典词干仅与其词典一样好。为了运作良好,这些词典必须包含大量单词,定期更新并随语言趋势而变化。通常,在提供字典时,它是不完整的,并且其某些条目已经过时了。
- 大小和性能,词典词干必须将其词典中的所有单词,前缀和后缀加载到内存中。这会占用大量RAM。低质量词典在删除前缀和后缀时也可能效率较低,这可能会大大减慢词干的处理速度。
control stemming 限制词干
有些时候,词干分析器会将拼写类似但是含义不同的词,定义为同一个词干。为了防止这种情况,可以使用control stemming,如下所示:
stemmer_override
,可让您定义用于阻止特定令牌的规则。
keyword_marker
,将指定的标记标记为关键字。关键字令牌不会被后续的词干令牌过滤器阻止。
conditional
,可用于将令牌标记为关键字,类似于keyword_marker过滤器。
对于内置的语言分析器,您还可以使用参数stem_exclusion
来制定不会被阻之的单词列表。
Token graphs 标记图
当tokenizer将文本转化成标记流时,他还会记录以下内容:
- 每个标记的位置
- 位置之间的间隔
使用这些信息,您可以为流创建一个有向无环图,成为tonen graphs。在图中,每个位置代表一个节点。每个标记都表示只想下一个位置的边或弧。
一些标记过滤器可以将新的标记添加到现有的流中。同义词通常与现有的标记的位置相同。
配置文本分析
在默认情况下,Elasticsearch 使用默认的标准分析器,对于大多数语言,是开箱即用的。
如果默认的标准分析器不符合您的需求,可以尝试使用Elasticsearch 提供的其他分析器,内置分析仪不需要配置,但是可以使用一些支持选项来调整其行为。例如,您可以为标准分析器配置要删除的自定义停用词列表。
测试分析器
最简单的用法
POST _analyze
{
/*指定分析器*/
"analyzer": "whitespace",
/*指定要分析的文本*/
"text": "The quick brown fox."
}
指定其他参数
- 一个分词器
- 零个或多个标记过滤器
- 零个或多个字符过滤器
POST _analyze
{
"tokenizer": "standard",
"filter": [ "lowercase", "asciifolding" ],
"text": "Is this déja vu?"
}
使用现有的索引中文本字段的分析器
PUT my_index
{
"settings": {
"analysis": {
"analyzer": {
"std_folded": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"lowercase",
"asciifolding"
]
}
}
}
},
"mappings": {
"properties": {
"my_text": {
"type": "text",
"analyzer": "std_folded"
}
}
}
}
GET my_index/_analyze
{
"analyzer": "std_folded",
"text": "Is this déjà vu?"
}
GET my_index/_analyze
{
"field": "my_text",
"text": "Is this déjà vu?"
}
配置标准分析器
标准分析器可以开箱即用,但也可以修改一些配置来控制它的行为。例如,可以将标准分析器配置为支持停用词列表。参考下面示例:
- 在标准分析器的基础上定义了一个
std_english
分析器,但是配置为删除英语停用词的预定义列表 - 第一个
GET
示例中,my_text
字段直接使用标准分词器,没有被移除停止使用后的词,结果是[the, old, brown, cow]
3.第二个GET示例中,my_text.english
使用std_english
分词器,会移除停止使用的词,结果是[old, brown, cow]
PUT my_index
{
"settings": {
"analysis": {
"analyzer": {
"std_english": {
"type": "standard",
"stopwords": "_english_"
}
}
}
},
"mappings": {
"properties": {
"my_text": {
"type": "text",
"analyzer": "standard",
"fields": {
"english": {
"type": "text",
"analyzer": "std_english"
}
}
}
}
}
}
POST my_index/_analyze
{
"field": "my_text",
"text": "The old brown cow"
}
POST my_index/_analyze
{
"field": "my_text.english",
"text": "The old brown cow"
}
自定义一个分析器
当标准分析器无法满足使用需求是,可以自定义一个分析器:
- 一个分词器
- 零个或多个标记过滤器
- 零个或多个字符过滤器
参数
参数 | 含义 |
---|---|
tokenizer | 内置或自定义的标记器。(需要) |
char_filter | 内置或自定义字符过滤器的可选数组 。 |
filter | 内置或自定义标记过滤器的可选数组 。 |
position_increment_gap | 在为文本值数组建立索引时,Elasticsearch在一个值的最后一项和下一个值的第一项之间插入一个假的“空白”,以确保词组查询与来自不同数组元素的两项不匹配。默认为100。查看position_increment_gap更多。 |
自定义过滤器示例
指定分析器
Elasticsearch 提供了多种方法来指定内置或自定义的分析器:
- 按text字段,索引或查询
- 用于索引或搜索
把事情简单化,在不同层次和不同的时间,指定分析仪的灵活性是伟大的… 不过也要仅在需要时它。
在大多数情况下,一种简单的方法最有效:为每个text
字段指定一个分析器,如为 字段指定分析器中所述。这种方法与Elasticsearch的默认行为很好地配合使用,使您可以使用同一分析器进行索引和搜索。它还使您可以使用get mapping API
快速查看哪个分析器应用于哪个字段。如果通常不为索引创建映射,则可以使用 索引模板来达到类似的效果。
Elasticsearch 如何确定索引分析器
Elasticsearch 依次检查以下参数,来确定要使用的索引分析器:
1. analyzer
,字段映射参数
2. analysis.analyzer.default
,默认分析器
3. 如未指定,则使用标准分析器
如何确定搜索分析器
在大多数情况下,无需指定其他搜索分析器。这样做可能会对相关性产生负面影响,并导致意外的搜索结果。
如果您选择指定一个单独的搜索分析器,我们建议您在部署到生产环境之前彻底 测试您的分析配置。
在搜索时,Elasticsearch通过依次检查以下参数来确定要使用的分析器:
analyzer
搜索查询中 的参数。请参阅为查询指定搜索分析器。search_analyzer
字段 的映射参数。请参阅为字段指定搜索分析器。analysis.analyzer.default_search
。请参阅为索引指定默认搜索分析器。analyzer
字段 的映射参数。请参阅为字段指定分析器。- 如未指定,则使用标准分析器
可以点击查看示例
内置分析器
- 标准分析器(
Standard Analyzer
):根据Unicode文本分段算法的定义,分析器将文本划分为单词边界上的多个术语。它删除大多数标点符号,小写术语,并支持停用词 - 简单分析器(
Simple Analyzer
):当分析器遇到非字母的字符时,它将文本划分成为多个术语,将所有术语转化为小写 - 空白分析器(
Whitespace Analyzer
):任何空白字符都作为分隔符,将文本划分为术语 - 停用分析器(
Stop Analyzer
):和简单分析器类似,而且支持去除停用词。 - 关键字分析器(
Keyword Analyzer
):将整个文本视为一个术语 - 模式分析器(
Pattern Analyzer
):使用正则表达式,将文本分割。支持小写文本,和停用词 - 语言分析器(
Language Analyzer
):对于特定的语言 - 指纹分析器(
Fingerprint Analyzer
):可创建可用于重复检测的指纹。 - 自定义分析器:如果你没有找到一个分析仪适合您的需求,您可以创建一个分析器,结合相应的字符过滤器, 标记生成器,和标记过滤。
内置分词器
内置标记过滤器
内置字符过滤器
字符过滤器用于预处理字符流,然后再将其传递给令牌生成器。
字符过滤器将原始文本作为字符流接收,并且可以通过添加,删除或更改字符来转换流。例如,可以使用字符过滤器将印度阿拉伯数字(٠ ١٢٣٤٥٦٧٨ ٩)转换为其等效的阿拉伯语-拉丁语(0123456789),或从流中剥离HTML元素。
Elasticsearch有许多内置的字符过滤器,可用于构建 自定义分析器。
- HTML字符过滤器,该
html_strip
字符过滤带出HTML元素,比如像和解码HTML实体&。 - 映射字符过滤器,该
mapping
字符过滤器替换指定更换指定的字符串中的任何事件。 - 正则表达式替换字符过滤器,
pattern_replace
字符过滤器将所有与正则表达式匹配的字符替换为指定的替换。