ElasticSearch之Analysis介绍
我们在前面的文章中介绍了ElasticSearch的Cluster和存储相关的基础,但总的来说,那些都还是一个类似NoSQL的数据库。而ElasticSearch真正厉害的部分还是在search这个方面,也就是说它不仅仅可以存储文本,还可以把这些文本的内容进行index,从而服务于Search。
ElasticSearch的三大部分
要理解ElasticSearch,首先我们需要关注其很重要的三个部分:
- Mapping:就是数据的每一个域都是如何解析的。
- Analysis:就是一个全文本是如何进行分析并使它可以被搜索的。
- Query DSL:ElasticSearch使用的查询语言。
本文就来详细介绍一下其中的Analysis的过程。
精确值和全文本
总得来说ElasticSearch把数据分成了两个类型,一个是精确值,一个是全文本。
所谓的精确值就是它精确表示的值。比如说一个日期或者一个userID,就像2018-10-01和2018进行精确值比较他们就是不一样的,再比如Apple和apple进行精确值比较也是不一样的。所以说精确值的查询和比较简单,一样就是一样,不一样就是不一样,比如下面这个查询:
![](https://donggeitnote.com/wp-content/uploads/2021/08/image-23.png)
而另外一个是全文本,它通常是以一种人类理解的语言来表示的,所以一般来说我们很难回答文本是否和查询是一样的或者匹配的,我们一般会说这个文本和查询的匹配程度是怎么样的,也就是说两者的相关度是多少。所以这个时候,我们不是进行精确的 比较,而是进行意图的识别:
- 一个查询“US”的query我们需要返回包含“Unite State”的文本。
- 一个查询“jump”的query和Jumped,jumps,jumping甚至leap都是在一定程度上匹配的。
- 我们上文提到apple和Apple,或者人名的大小写比如josh ling和Josh Ling也是应该匹配的。
那么ElasticSearch是如何做到这些的呢,它会首先分析文本,然后使用分析后的结果来创建inverted index,下面我们就来详细讨论一下Inverted index。
Inverted Index
Inverted Index是一种数据结构,它专门用来服务快速搜索的。它首先是一个文本中出现的独立的单词列表,然后每个单词对应一个list,这个list中包含了所有有这个单词的文本。我们来看下面这个例子,假设我们有下面两个文本内容:
- The quick brown fox jumped over the lazy dog
- Quick brown foxes leap over lazy dogs in summer
我们创建Inverted index的时候,会首先把这些内容分成单独的单词(又称之为terms或者tokens),然后创建一个单词的list,并且每个单词在对应一个文本list,结果如下所示:
![](https://donggeitnote.com/wp-content/uploads/2021/08/image-24.png)
这个时候我们搜索“quick brown”的时候,就只要去看这两个单词的结果了(类似一个值为列表的hash查询):
![](https://donggeitnote.com/wp-content/uploads/2021/08/image-25.png)
我们可以看到两个文本中都有我们想要查询的单词,而且Doc1中两个单词都出现了,Doc2中只出现了一个单词,所以假如我们使用一个很简单的算法来判断相似度,比如就比较谁出现的数目多的话,那我们可能会认为Doc1的匹配度更好一点,毕竟两个单词在它里面都出现了。
但是当我们仔细回想之后会发现,这样简单的比较好像有点问题:
- 我们上面把Quick和quick认为是两个term,而假如我们人来看的话,可能会认为他们其实是一样的。
- fox和foxes以及dog和dogs其实也是很类似的,只是单复数的差别而已。
- jumped和leap虽然是不同的单词,但他们是同义词。
比如说假如我们这时候搜索+Quick +fox就会遇到上面的问题(这里的+意味着这个单词必须存在),这个时候就没有结果,因为上面两个文本都没有这两个单词同时出现的情况。而从我们人的分析来看,我们希望的可能是上面两个文本都匹配到我们的查询。如何解决这个问题呢?我们可以normalize这写term到标准的格式,比如说:
- Quick可以全部变成小写的quick
- Foxes可以变成它的根单词fox,同样的dogs也可以变成dog
- jumped和leap是同义词,就可以都变成jump。
这样处理之后我们的index就变成了下面这个样子:
![](https://donggeitnote.com/wp-content/uploads/2021/08/image-26.png)
也许你会说这个时候假如我们搜索+Quick +fox还是没有结果啊,因为我们没有Quick这个单词了。其实你稍微想一下应该就会发现,我们可以把同样的处理也应用到搜索的关键词上来,我们的搜索就变成了+quick +fox,这样一来两个文本就都匹配了。
这里的tokenization和normalization就是我们通常说的analysis。
Analysis
我们简单总结一下就会发现其实上面的Analysis包含了两个部分:
- 首先把一个文本块转变成单独的terms,从而可以更好地应用于inverted index。
- 规格化(normalizing)这些terms到一个标准的格式,从而改进他们的搜索性能。
这个功能其实是通过Analyzer来实现,你其实可以理解它为一个wrapper,主要有以下三个功能:
- Character filter:在字符串到tokenizer之前对字符先进行的预处理,比如把HTML中的div,a等tag去除掉,或者把&转变成and等等
- Tokenizer:这一步就是把字符转变成一个个terms(单词)。简单的tokenize可以根据空格或者标点符号进行划分。
- Token filters。在有了一个个terms之后,会进行最后的filter,比如把所有的单词都改成小写,或者同义词的变换,或者把一些禁止的词去除掉等等。
ElasticSearch支持很多character filter,tokenizer以及token filters。我们设置可以把它们结合起来使用。这个我们会在后面的文章中再详细介绍。我们这里介绍几个内置的analyzer。
内置Analyzer
我们来看内置的analyzer是如何处理字符的,假设我们有下面这个字符串:
![](https://donggeitnote.com/wp-content/uploads/2021/08/image-27.png)
标准Analyzer
标准Analyzer是ElasticSearch默认的analyzer,通常来说也是最佳的analyzer。它可以把文本根据单词进行split,并且会去除标点符号,并把所有的term换成小写,所以结果如下所示:
![](https://donggeitnote.com/wp-content/uploads/2021/08/image-28.png)
简单Analyzer
简单Analyzer会把文本根据所有不是字母的符号进行split,然后换成小写,所以得到的结果如下,我们可以看到数字5没了,set_trans也被分成了两个term,因为它们之间的下划线不是字母。
![](https://donggeitnote.com/wp-content/uploads/2021/08/image-29.png)
空格Analyzer
这个顾名思义,就是根据空格来进行split,然后在换成小写,所以结果如下:
![](https://donggeitnote.com/wp-content/uploads/2021/08/image-30.png)
语言Analyzer
每个语言都有其特色,它会根据语言的特色来split字符串,比如说使用英语分析中,一些stopwords比如and,the其实并没有什么意义,就会被去除掉。我们使用英语分析之后的结果如下,你会发现the,to,by等词被去除了。
![](https://donggeitnote.com/wp-content/uploads/2021/08/image-31.png)
总结
本文介绍了ElasticSearch中的Analysis的过程,并介绍了常见的几种Analyzer,希望大家再阅读之后能有所理解。
1 Response
[…] 我们在《ElasticSearch之Analysis介绍》中介绍了为了使得文本可以被搜索,我们需要位置创建inverted Index,关于它的概念我们就不详细介绍了。这里一个很有趣的问题就是不变性。我们说希望写入到磁盘中的Inverted Index不再变化,这样的特性会带来很多好处: […]