ES 深入浅出系列(四)深入理解es的分词流程

477 阅读4分钟

在今天的文章中,我们来进一步了解 analyzer。 analyzer 执行将输入字符流分解为token的过程,它一般发生在两个场合:

  • 在 indexing 的时候,也即在建立索引的时候
  • 在 searching 的时候,也即在搜索时,分析需要搜索的词语

image.png

什么是 analysis?

分析是 Elasticsearch 在文档发送之前对文档正文执行的过程,以添加到反向索引中(inverted index)。 在将文档添加到索引之前,Elasticsearch 会为每个分析的字段执行许多步骤:

  • Character filtering (字符过滤器): 使用字符过滤器转换字符
  • Breaking text into tokens (把文字转化为标记): 将文本分成一组一个或多个标记
  • Token filtering:使用标记过滤器转换每个标记
  • Token indexing:把这些标记存于索引中

接下来我们将更详细地讨论每个步骤,但首先让我们看一下图表中总结的整个过程。 下图显示了 “share your experience with NoSql & big data technologies" 为分析的标记:share, your, experience, with, nosql, big, data,tools 及 technologies。

image.png

上面所展示的是一个由 character 过滤器,标准的 tokenizer 及 Token filter 组成的定制 analyzer。上面的这个图非常好,它很简洁地描述一个 analyzer 的基本组成部分,以及每个部分所需要表述的东西。

经过 analyzer 处理过后的文档最终以 Inverted Index 的形式保存于 Elasticsearch 中:

image.png

每当一个文档被 ingest 节点纳入,它需要经历如下的步骤,才能最终把文档写入到 Elasticsearch的 数据库中:

image.png

上面中间的那部分就叫做 analyzer,即分析器。它有三个部分组成:Char Filters, Tokenizer 及 Token Filter。它们的作用分别如下:

  • Char Filter: 字符过滤器的工作是执行清除任务,例如剥离 HTML 标记,还有上面的把 “&” 转换为 “and” 字符串
  • Tokenizer: 下一步是将文本拆分为称为标记的术语。 这是由 tokenizer 完成的。 可以基于任何规则(例如空格)来完成拆分。 有关 tokenizer 的更多详细信息,请访问以下URL:www.elastic.co/guide/en/el…
  • Token filter: 一旦创建了 token,它们就会被传递给 token filter,这些过滤器会对 token 进行规范化。 Token filter 可以更改 token,删除术语或向 token 添加术语。

image.png

一个 analyzer 有且只有一个 tokenizer,有0个或一个以上的 char filter 及 token filter。

Elasticsearch 已经提供了比较丰富的开箱即用 analyzer。我们可以自己创建自己的 token analyzer,甚至可以利用已经有的 char filter,tokenizer 及 token filter 来重新组合成一个新的 analyzer,并可以对文档中的每一个字段分别定义自己的 analyzer。

在默认的情况下,standard analyzer 是 Elasticsearch 的缺省分析器:

  • 没有 Char Filter
  • 使用 standard tokonizer
  • 把字符串变为小写,同时有选择地删除一些 stop words 等。默认的情况下 stop words 为 none,也即不过滤任何 stop words。

image.png

image.png

关于停用词

在信息检索中,停用词 是为节省存储空间和提高搜索效率,处理文本时自动过滤掉某些字或词,这些字或词即被称为Stop Words(停用词)。

停用词大致分为两类。一类是语言中的功能词,这些词极其普遍而无实际含义,比如“the”、“is“、“which“、“on”等。另一类是词汇词,比如'want'等,这些词应用广泛,但搜索引擎无法保证能够给出真正相关的搜索结果,难以缩小搜索范围,还会降低搜索效率。

实践中,通常把这些词从问题中过滤,从而节省索引的存储空间、提高搜索性能。

但是在实际语言环境中,停用词有时也有用的。比如,莎士比亚的名句:“To be or not to be.”所有的词都是停用词。特别当停用词和通配符(*)同时使用的时候,问题就来了:“the”、“is“、“on”还是停用词吗?

实际运用中,没有一个解决方案是100%完美的。很多时候需要我们根据实际用例作相应的调整和折中,来达到期望的结果。在这个时候,需要用80/20原则,把目标专注在提高用户体验上。

如何启动停用词

在默认的情况下,standard 分词器中的 stopwords filter 是禁用的。我们可以使用如下的方法来进行启动:

PUT my_index_with_stopwords
{
  "settings": {
    "analysis": {
      "analyzer": {
      "standard_with_stopwords":{ 
      "type":"standard", 
      "stopwords":"_english_" 
      }
      }
    }
  }
}

在上面,我们通过设置 stopwords 的方法启动了 stop filter。我们可以使用如下的测试命令来测试一下:

POST my_index_with_stopwords/_analyze
{
  "text": "This is a wonderful experience and I think it is the best solution",
  "analyzer": "standard_with_stopwords"
}

上面的命令的结果为:

{
  "tokens": [
    {
      "token": "wonderful",
      "start_offset": 10,
      "end_offset": 19,
      "type": "<ALPHANUM>",
      "position": 3
    },
    {
      "token": "experience",
      "start_offset": 20,
      "end_offset": 30,
      "type": "<ALPHANUM>",
      "position": 4
    },
    {
      "token": "i",
      "start_offset": 35,
      "end_offset": 36,
      "type": "<ALPHANUM>",
      "position": 6
    },
    {
      "token": "think",
      "start_offset": 37,
      "end_offset": 42,
      "type": "<ALPHANUM>",
      "position": 7
    },
    {
      "token": "best",
      "start_offset": 53,
      "end_offset": 57,
      "type": "<ALPHANUM>",
      "position": 11
    },
    {
      "token": "solution",
      "start_offset": 58,
      "end_offset": 66,
      "type": "<ALPHANUM>",
      "position": 12
    }
  ]
}

很显然,this is the 等这些常见的词不见了。