ElasticSearch之Analysis介绍

我们在前面的文章中介绍了ElasticSearch的Cluster和存储相关的基础,但总的来说,那些都还是一个类似NoSQL的数据库。而ElasticSearch真正厉害的部分还是在search这个方面,也就是说它不仅仅可以存储文本,还可以把这些文本的内容进行index,从而服务于Search。

ElasticSearch的三大部分

要理解ElasticSearch,首先我们需要关注其很重要的三个部分:

  1. Mapping:就是数据的每一个域都是如何解析的。
  2. Analysis:就是一个全文本是如何进行分析并使它可以被搜索的。
  3. Query DSL:ElasticSearch使用的查询语言。

本文就来详细介绍一下其中的Analysis的过程。

精确值和全文本

总得来说ElasticSearch把数据分成了两个类型,一个是精确值,一个是全文本。

所谓的精确值就是它精确表示的值。比如说一个日期或者一个userID,就像2018-10-01和2018进行精确值比较他们就是不一样的,再比如Apple和apple进行精确值比较也是不一样的。所以说精确值的查询和比较简单,一样就是一样,不一样就是不一样,比如下面这个查询:

而另外一个是全文本,它通常是以一种人类理解的语言来表示的,所以一般来说我们很难回答文本是否和查询是一样的或者匹配的,我们一般会说这个文本和查询的匹配程度是怎么样的,也就是说两者的相关度是多少。所以这个时候,我们不是进行精确的 比较,而是进行意图的识别:

  • 一个查询“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中包含了所有有这个单词的文本。我们来看下面这个例子,假设我们有下面两个文本内容:

  1. The quick brown fox jumped over the lazy dog
  2. Quick brown foxes leap over lazy dogs in summer

我们创建Inverted index的时候,会首先把这些内容分成单独的单词(又称之为terms或者tokens),然后创建一个单词的list,并且每个单词在对应一个文本list,结果如下所示:

这个时候我们搜索“quick brown”的时候,就只要去看这两个单词的结果了(类似一个值为列表的hash查询):

我们可以看到两个文本中都有我们想要查询的单词,而且Doc1中两个单词都出现了,Doc2中只出现了一个单词,所以假如我们使用一个很简单的算法来判断相似度,比如就比较谁出现的数目多的话,那我们可能会认为Doc1的匹配度更好一点,毕竟两个单词在它里面都出现了。

但是当我们仔细回想之后会发现,这样简单的比较好像有点问题:

  1. 我们上面把Quick和quick认为是两个term,而假如我们人来看的话,可能会认为他们其实是一样的。
  2. fox和foxes以及dog和dogs其实也是很类似的,只是单复数的差别而已。
  3. jumped和leap虽然是不同的单词,但他们是同义词。

比如说假如我们这时候搜索+Quick +fox就会遇到上面的问题(这里的+意味着这个单词必须存在),这个时候就没有结果,因为上面两个文本都没有这两个单词同时出现的情况。而从我们人的分析来看,我们希望的可能是上面两个文本都匹配到我们的查询。如何解决这个问题呢?我们可以normalize这写term到标准的格式,比如说:

  • Quick可以全部变成小写的quick
  • Foxes可以变成它的根单词fox,同样的dogs也可以变成dog
  • jumped和leap是同义词,就可以都变成jump。

这样处理之后我们的index就变成了下面这个样子:

也许你会说这个时候假如我们搜索+Quick +fox还是没有结果啊,因为我们没有Quick这个单词了。其实你稍微想一下应该就会发现,我们可以把同样的处理也应用到搜索的关键词上来,我们的搜索就变成了+quick +fox,这样一来两个文本就都匹配了。

这里的tokenization和normalization就是我们通常说的analysis。

Analysis

我们简单总结一下就会发现其实上面的Analysis包含了两个部分:

  1. 首先把一个文本块转变成单独的terms,从而可以更好地应用于inverted index。
  2. 规格化(normalizing)这些terms到一个标准的格式,从而改进他们的搜索性能。

这个功能其实是通过Analyzer来实现,你其实可以理解它为一个wrapper,主要有以下三个功能:

  1. Character filter:在字符串到tokenizer之前对字符先进行的预处理,比如把HTML中的div,a等tag去除掉,或者把&转变成and等等
  2. Tokenizer:这一步就是把字符转变成一个个terms(单词)。简单的tokenize可以根据空格或者标点符号进行划分。
  3. Token filters。在有了一个个terms之后,会进行最后的filter,比如把所有的单词都改成小写,或者同义词的变换,或者把一些禁止的词去除掉等等。

ElasticSearch支持很多character filter,tokenizer以及token filters。我们设置可以把它们结合起来使用。这个我们会在后面的文章中再详细介绍。我们这里介绍几个内置的analyzer。

内置Analyzer

我们来看内置的analyzer是如何处理字符的,假设我们有下面这个字符串:

标准Analyzer

标准Analyzer是ElasticSearch默认的analyzer,通常来说也是最佳的analyzer。它可以把文本根据单词进行split,并且会去除标点符号,并把所有的term换成小写,所以结果如下所示:

简单Analyzer

简单Analyzer会把文本根据所有不是字母的符号进行split,然后换成小写,所以得到的结果如下,我们可以看到数字5没了,set_trans也被分成了两个term,因为它们之间的下划线不是字母。

空格Analyzer

这个顾名思义,就是根据空格来进行split,然后在换成小写,所以结果如下:

语言Analyzer

每个语言都有其特色,它会根据语言的特色来split字符串,比如说使用英语分析中,一些stopwords比如and,the其实并没有什么意义,就会被去除掉。我们使用英语分析之后的结果如下,你会发现the,to,by等词被去除了。

总结

本文介绍了ElasticSearch中的Analysis的过程,并介绍了常见的几种Analyzer,希望大家再阅读之后能有所理解。

You may also like...

1 Response

  1. September 29, 2021

    […] 我们在《ElasticSearch之Analysis介绍》中介绍了为了使得文本可以被搜索,我们需要位置创建inverted Index,关于它的概念我们就不详细介绍了。这里一个很有趣的问题就是不变性。我们说希望写入到磁盘中的Inverted Index不再变化,这样的特性会带来很多好处: […]

Leave a Reply

Your email address will not be published.