默认的,Elasticsearch对于所有文本分析使用标准文本分析器,标准分析器为大多数自然语言和用例提供开箱即用的支持。如果您选择按原样使用标准分析器,则不需要进一步配置。

如果标准分析器不能满足您的需求,请检查和测试Elasticsearch的其他内置分析器。内置的分析器不需要配置,但是一些支持选项可以用来调整它们的行为。例如,可以使用要移除的自定义停止词列表配置标准分析器。

如果没有内置分析器满足您的需求,您可以测试并创建一个自定义分析器。自定义分析器包括选择和组合不同的分析器组件,使您对过程有更大的控制。

分析器解剖

分析器——无论是内置的还是自定义的——只是一个包,它包含三个较低级的构建块:字符过滤器、标记器和标记过滤器。

内置的分析器将这些构建块预先打包到适合不同语言和文本类型的分析器中。Elasticsearch还公开了各个构建块,以便将它们组合起来定义新的定制分析器。

字符过滤器

字符过滤器以字符流的形式接收原始文本,并可以通过添加、删除或更改字符来转换字符流。例如,可以使用字符过滤器将印度教-阿拉伯数字(٠‎١٢٣٤٥٦٧٨‎٩‎)转换为阿拉伯-拉丁数字(0123456789),或者从流中去除像这样的HTML元素。

分析器可以有零个或多个字符过滤器,它们是按顺序应用的。

标记器

标记器接收字符流,将其分解为单个标记(通常是单个单词),并输出标记流。例如,只要看到任何空白,空白标记器就会将文本分割为标记。它会将文本"Quick brown fox!"转换成术语[Quick, brown, fox!]

标记器还负责记录每个术语的顺序或位置,以及该术语所代表的原始单词的开始和结束字符偏移量。

一个分析器必须有且只有一个标记器。

标记过滤器

标记过滤器接收标记流,并可以添加、删除或更改标记。例如,小写标记过滤器将所有标记转换为小写,停止标记过滤器从标记流中删除常用单词(停止词),同义词标记过滤器将同义词引入标记流。

标记过滤器不允许更改每个标记的位置或字符偏移量。

分析器可以有零个或多个标记过滤器,它们是按顺序应用的。

测试分析器

分析器API是查看分析器生成的术语的宝贵工具。内置分析器可以在请求中内联指定:

POST _analyze
{
  "analyzer": "whitespace",
  "text":     "The quick brown fox."
}

返回以下响应:

{
  "tokens": [
    {
      "token": "The",
      "start_offset": 0,
      "end_offset": 3,
      "type": "word",
      "position": 0
    },
    {
      "token": "quick",
      "start_offset": 4,
      "end_offset": 9,
      "type": "word",
      "position": 1
    },
    {
      "token": "brown",
      "start_offset": 10,
      "end_offset": 15,
      "type": "word",
      "position": 2
    },
    {
      "token": "fox.",
      "start_offset": 16,
      "end_offset": 20,
      "type": "word",
      "position": 3
    }
  ]
}

您还可以测试以下组合:

  • 一个标记器
  • 0或多个标记过滤器
  • 0或多个字符过滤器
POST _analyze
{
  "tokenizer": "standard",
  "filter":  [ "lowercase", "asciifolding" ],
  "text":      "Is this déja vu?"
}

返回以下响应:

{
  "tokens": [
    {
      "token": "is",
      "start_offset": 0,
      "end_offset": 2,
      "type": "<ALPHANUM>",
      "position": 0
    },
    {
      "token": "this",
      "start_offset": 3,
      "end_offset": 7,
      "type": "<ALPHANUM>",
      "position": 1
    },
    {
      "token": "deja",
      "start_offset": 8,
      "end_offset": 12,
      "type": "<ALPHANUM>",
      "position": 2
    },
    {
      "token": "vu",
      "start_offset": 13,
      "end_offset": 15,
      "type": "<ALPHANUM>",
      "position": 3
    }
  ]
}

位置和字符偏移量

可以看到从分析API的输出,分析不仅将文字转换成术语,他们也记录每一项的顺序或相对位置(用于短语查询或词近似查询),和每个术语的开始和结束字符偏移量原文(用于突出显示搜索片段)。

或者,当在特定索引上运行分析API时,可以引用自定义分析器:

PUT my-index-000001
{
  "settings": {
    "analysis": {
      "analyzer": {
        "std_folded": { 
          "type": "custom",
          "tokenizer": "standard",
          "filter": [
            "lowercase",
            "asciifolding"
          ]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "my_text": {
        "type": "text",
        "analyzer": "std_folded" 
      }
    }
  }
}

GET my-index-000001/_analyze 
{
  "analyzer": "std_folded", 
  "text":     "Is this déjà vu?"
}

GET my-index-000001/_analyze 
{
  "field": "my_text", 
  "text":  "Is this déjà vu?"
}

返回以下响应:

{
  "tokens": [
    {
      "token": "is",
      "start_offset": 0,
      "end_offset": 2,
      "type": "<ALPHANUM>",
      "position": 0
    },
    {
      "token": "this",
      "start_offset": 3,
      "end_offset": 7,
      "type": "<ALPHANUM>",
      "position": 1
    },
    {
      "token": "deja",
      "start_offset": 8,
      "end_offset": 12,
      "type": "<ALPHANUM>",
      "position": 2
    },
    {
      "token": "vu",
      "start_offset": 13,
      "end_offset": 15,
      "type": "<ALPHANUM>",
      "position": 3
    }
  ]
}
  1. 定义了一个自定义分析器名字为std_folded
  2. 域my_text使用std_fold分析器。
  3. 要引用此分析器,分析API必须指定索引名称。
  4. 按名称引用分析器。
  5. 应用域my_text使用的分析器。

配置内建分析器

内置的分析器可以直接使用,无需任何配置。然而,其中一些支持配置选项来改变它们的行为。例如,标准分析器可以配置为支持停止词列表:

PUT my-index-000001
{
  "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-000001/_analyze
{
  "field": "my_text", 
  "text": "The old brown cow"
}

POST my-index-000001/_analyze
{
  "field": "my_text.english", 
  "text": "The old brown cow"
}
  • 我们定义了基于标准分析器的std_english分析器,但是配置为删除预定义的英语停止词列表。
  • my_text域直接使用标准分析器,不需要任何配置。在这个域中没有停止词将被删除。由此产生的词是:[ the, old, brown, cow ]
  • my_text.english字段使用std_english分析器,因此英语停止词将被删除。结果是:[ old, brown, cow ]

创建自定义分析器

当内置分析器不能满足您的需求时,您可以创建一个自定义分析器,使用以下适当的组合:

  • 0或多个字符过滤器
  • 一个标记器
  • 0或多个标记过滤器

配置

自定义分析器接收以下参数:

参数

描述

type

分析器类型。接收内建分析器类型。对于自定义分析器使用custom或忽略该参数。

tokenizer

内建或自定义标记器(必需)

char_filter

内建或自定义字符过滤器数组(可选)

filter

内建或自定义标记过滤器数组(可选)

position_increment_gap

当索引一个文本值数组时,Elasticsearch会在一个值的最后一项和下一个值的第一个项之间插入一个假的“间隙”,以确保短语查询不会匹配来自不同数组元素的两个项。默认为100。更多信息请参见position_increment_gap。

示例配置

下面是一个结合了以下内容的例子:

字符过滤器

  • HTML Strip Character Filter

标记器

  • Standard Tokenizer

标记器过滤器

  • Lowercase Token Filter
  • ASCII-Folding Token Filter
PUT my-index-000001
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_custom_analyzer": {
          "type": "custom", 
          "tokenizer": "standard",
          "char_filter": [
            "html_strip"
          ],
          "filter": [
            "lowercase",
            "asciifolding"
          ]
        }
      }
    }
  }
}

POST my-index-000001/_analyze
{
  "analyzer": "my_custom_analyzer",
  "text": "Is this <b>déjà vu</b>?"
}
  • 对于自定义分析器,type字段使用custom或忽略type参数

上面的例子产生了以下词语:

[ is, this, deja, vu ]

前面的示例使用了默认配置的标记器、标记过滤器和字符过滤器,但是可以创建每种自定义配置的版本,并在自定义分析器中使用它们。

下面是一个更复杂的例子:

字符过滤器

  • Mapping Character Filter,配置为使用_happy_替换:),使用_sad_替换:(

标记器

  • Pattern Tokenizer,配置为按标点字符分割

标记过滤器

  • Lowercase Token Filter
  • Stop Token Filter,配置为使用预定义的英文停止词列表

以下是一个例子:

PUT my-index-000001
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_custom_analyzer": { 
          "char_filter": [
            "emoticons"
          ],
          "tokenizer": "punctuation",
          "filter": [
            "lowercase",
            "english_stop"
          ]
        }
      },
      "tokenizer": {
        "punctuation": { 
          "type": "pattern",
          "pattern": "[ .,!?]"
        }
      },
      "char_filter": {
        "emoticons": { 
          "type": "mapping",
          "mappings": [
            ":) => _happy_",
            ":( => _sad_"
          ]
        }
      },
      "filter": {
        "english_stop": { 
          "type": "stop",
          "stopwords": "_english_"
        }
      }
    }
  }
}

POST my-index-000001/_analyze
{
  "analyzer": "my_custom_analyzer",
  "text": "I'm a :) person, and you?"
}
  1. 为索引分配一个默认的自定义分析器my_custom_analyzer。这个分析器使用自定义的标记器、字符过滤器和标记过滤器,这些在请求后面定义。这个分析器也省略了类型type参数。
  2. 定义了自定义的punctuation标记器
  3. 定义了自定义的emoticons字符过滤器
  4. 定义了自定义的english_stop标记过滤器

上面的例子产生了以下词语:

[ i'm, _happy_, person, you ]

使用分析器

Elasticsearch提供了多种方法来指定内置或自定义分析器。

  • 通过text域、索引或查询
  • 在索引或查询时机

保持简单

在不同级别和不同时间指定分析程序的灵活性很棒,但只在需要的时候。

在大多数情况下,一种简单的方法效果最好:为每个文本域指定一个分析器,如为域指定分析程序中所述。

这种方法可以很好地配合Elasticsearch的默认行为,让您使用相同的分析器进行索引和搜索。它还允许您使用get mapping API快速查看哪个分析器应用于哪个域。

如果您通常不为索引创建映射,那么可以使用索引模板来实现类似的效果。

Elasticsearch如何确定索引分析器

Elasticsearch通过检查以下参数来决定使用哪个索引分析器:

  1. 分析器的域映射参数。请参阅指定域的分析器。
  2. analysis.analyzer.default索引设置。请参阅指定索引的默认分析器。

如果没有指定这些参数,则使用标准分析器。

指定域的分析器

当映射索引时,你可以使用分析器映射参数来为每个text域指定一个分析器。

下面的创建索引API请求设置whitespace分析器作为title域的分析器。

PUT my-index-000001
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "whitespace"
      }
    }
  }
}
指定索引默认的分析器

除了域级分析器外,您还可以设置使用analysis.analyzer.default设置的后备分析器。

下面的创建索引API请求设置simple分析器作为索引my-index-000001的后备分析器。

PUT my-index-000001
{
  "settings": {
    "analysis": {
      "analyzer": {
        "default": {
          "type": "simple"
        }
      }
    }
  }
}

Elasticsearch如何确定搜索分析器

警告:在大多数情况下,没有必要指定不同的搜索分析器。这样做可能会对相关性产生负面影响,并导致意想不到的搜索结果。

如果您选择指定一个单独的搜索分析器,我们建议您在部署到生产环境之前彻底测试分析配置。

在搜索时,Elasticsearch通过检查以下参数来决定使用哪个分析器:

  1. 搜索查询中的分析器参数。请参阅指定查询的搜索分析器。
  2. 域的search_analyzer映射参数。请参阅指定字段的搜索分析器。
  3. analysis.analyzer.default_search索引设置。请参阅指定索引的默认搜索分析器。
  4. 分析器对于域的映射参数。请参阅指定域的分析器。

如果没有指定这些参数,则使用标准分析仪。

指定查询的搜索分析器

在编写全文查询时,可以使用analyzer参数指定搜索分析器。如果提供,将覆盖任何其他搜索分析器。

下面的搜索API请求将stop分析器设置为match查询的搜索分析器。

GET my-index-000001/_search
{
  "query": {
    "match": {
      "message": {
        "query": "Quick foxes",
        "analyzer": "stop"
      }
    }
  }
}
指定域的搜索分析器

在映射索引时,可以使用search_analyzer映射参数为每个文本域指定搜索分析器。

如果提供了搜索分析器,则还必须使用analyzer参数指定索引分析器。

下面的创建索引API请求将simple分析器设置为title域的搜索分析器。

PUT my-index-000001
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "whitespace",
        "search_analyzer": "simple"
      }
    }
  }
}
指定索引的默认搜索分析器

在创建索引时,可以使用analysis.analyzer.default_search设置设置默认搜索分析器。

如果提供了搜索分析器,还必须使用analysis.analyzer.default设置指定默认索引分析器。

下面的创建索引API请求将whitespace分析器设置为my-index-000001索引的默认搜索分析器。

PUT my-index-000001
{
  "settings": {
    "analysis": {
      "analyzer": {
        "default": {
          "type": "simple"
        },
        "default_search": {
          "type": "whitespace"
        }
      }
    }
  }
}