词条(term)查询和全文(fulltext)查询最大的不同之处是:全文查询首先分析(Analyze)查询字符串,使用默认的分析器分解成一系列的分词,term1,term2,termN,然后从索引中搜索是否有文档包含这些分词中的一个或多个。
所以,在基于全文的检索里,ElasticSearch引擎会先分析(analyze)查询字符串,将其拆分成小写的分词,只要已分析的字段中包含词条的任意一个,或全部包含,就匹配查询条件,返回该文档;如果不包含任意一个分词,表示没有任何文档匹配查询条件。
这里就牵涉到了ES里很重要的概念,文本分析,当然对应非text类型字段来说,本身不存在文本数据词项提取的问题,所以没有文本分析的问题。
文本分析的过程
分析(analysis )是在文档被发送并加入倒排索引之前,Elasticsearch在其主体上进行的操作。在文档被加入索引之前,Elasticsearch让每个被分析字段经过一系列的处理步骤:
- 字符过滤–使用字符过滤器转变字符。
- 文本切分为分词—将文本切分为单个或多个分词。
- 分词过滤—使用分词过滤器转变每个分词。
- 分词索引–将这些分词存储到索引中。
字符过滤
Elasticsearch首先运行字符过滤器(char filter)。这些过滤器将特定的字符序列转变为其他的字符序列。这个可以用于将 HTML从文本中剥离,或者是将任意数量的字符转化为其他字符。
例如将“I love u 2”这种缩写的短消息纠正为“I love you too”。
切分为分词
在应用了字符过滤器之后,文本需要被分割为可以操作的片段。底层的Lucene是不会对大块的字符串数据进行操作。相反,它处理的是被称为分词(token)的数据。
分词是从文本片段生成的,可能会产生任意数量(甚至是0)的分词。例如,在英文中一个通用的分词是标准分词器,它根据空格、换行和破折号等其他字符,将文本分割为分词。在我们的例子里,这种行为表现为将字符串“I like ELK,it
include Elasticsearch&LogStash&Kibana”分解为分词 I like ELK it include Elasticsearch and LogStash Kibana。
分词过滤器
一旦文本块被转换为分词,Elasticsearch将会对每个分词运用分词过滤器(token filter)。 这些分词过滤器可以将一个分词作为输入,然后根据需要进行修改,添加或者是删除。最为有用的和常用的分词过滤器是小写分词过滤器,它将输人的分词变为小写,确保在搜索词条“nosql"的时候,可以发现关于“NoSQL"的数据。分词可以经过多于1个的分词过滤器,每个过滤器对分词进行不同的操作,将数据塑造为最佳的形式,便于之后的索引。
分词索引
当分词经历了零个或者多个分词过滤器,它们将被发送到Lucene进行文档的索引。这些分词组成了倒排索引。
配置分析器
字符过滤器、分词器、分词过滤器统称为分析器(analyzer),它可以定义为零个或多个字符过滤器、1个分词器、零个或多个分词过滤器。Elasticsearch中提供了很多预定义的分析器,我们可以直接使用它们而无须构建自己的分析器。
配置分析器可以使用_analyze接口:
GET /_analyze
POST /_analyze
GET /<index>/_analyze
POST /<index>/_analyze
可以使用_analyze API来测试analyzer如何解析我们的字符串的。
因为文本分词会发生在两个地方:
- 创建索引:当索引文档字符类型为text时,在建立索引时将会对该字段进行分词;
- 搜索:当对一个text类型的字段进行全文检索时,会对用户输入的文本进行分词。
所以这两个地方都可以对分词进行配置。
创建索引时
ES将按照下面顺序来确定使用哪个分词器:
- 先判断字段属性是否有设置分词器,如果有,则使用字段属性上的分词器设置;
- 如果索引上设置了分词器,则使用索引上设置的分词器;
- 如果上面两个都未设置,则使用ES全局默认的standard分词器。
为索引设置默认分词器:
put test_index
{
"settings": {
"analysis": {
"analyzer": {
"default": {
"type": "simple"
}
}
}
}
}
还可以为索引配置内置分词器,并修改内置的部分选项修改它的行为:
put test_index2
{
"settings": {
"analysis": {
"analyzer": {
"my_analyzer": {
"type": "standard",
"stopwords": [
"the",
"a",
"an",
"this",
"is"
]
}
}
}
}
}
如何为字段指定内置分词器:
put test_index3
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "standard",
"search_analyzer": "simple"
}
}
}
}
甚至还可以自定义分词器。
我们综合来看看分词的设置,并且通过_analyzer接口来测试分词的效果:
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"
}
}
}
}
}
}
我们首先,在索引my_index中配置了一个分析器std_english,std_english中使用了内置分析器standard,并将standard 的停止词模式改为英语模式_english_(缺省是没有的),对字段my_text配置为多数据类型,分别使用了两种分析器,standard和std_english。
POST /my_index/_analyze
{
"field": "my_text",
"text": "The old brown cow"
}
输出结果:
{
"tokens" : [
{
"token" : "the",
"start_offset" : 0,
"end_offset" : 3,
"type" : "<ALPHANUM>",
"position" : 0
},
{
"token" : "old",
"start_offset" : 4,
"end_offset" : 7,
"type" : "<ALPHANUM>",
"position" : 1
},
{
"token" : "brown",
"start_offset" : 8,
"end_offset" : 13,
"type" : "<ALPHANUM>",
"position" : 2
},
{
"token" : "cow",
"start_offset" : 14,
"end_offset" : 17,
"type" : "<ALPHANUM>",
"position" : 3
}
]
}
POST /my_index/_analyze
{
"field": "my_text.english",
"text": "The old brown cow"
}
输出结果:
{
"tokens" : [
{
"token" : "old",
"start_offset" : 4,
"end_offset" : 7,
"type" : "<ALPHANUM>",
"position" : 1
},
{
"token" : "brown",
"start_offset" : 8,
"end_offset" : 13,
"type" : "<ALPHANUM>",
"position" : 2
},
{
"token" : "cow",
"start_offset" : 14,
"end_offset" : 17,
"type" : "<ALPHANUM>",
"position" : 3
}
]
}
通过上述运行我们可以看到,分析器std_english中的The被删除,而standard中的并没有。这是因为my_text.english配置了单独的停止词。
文档搜索时
文档搜索时使用的分析器有一点复杂,它依次从如下参数中如果查找文档分析器:
- 搜索时指定analyzer参数
- 创建索引时指定字段的search_analyzer属性
- 创建索引时字段指定的analyzer属性
- 创建索引时setting里指定的analysis.analyzer.default_search
- 如果都没有设置则使用standard分析器
搜索时指定analyzer查询参数:
GET my_index/_search
{
"query": {
"match": {
"message": {
"query": "Quick foxes",
"analyzer": "stop"
}
}
}
}
指定字段的analyzer和seach_analyzer:
PUT my_index
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "whitespace",
"search_analyzer": "simple"
}
}
}
}
指定索引的默认搜索分词器
PUT test_index4{ "settings": { "analysis": { "analyzer": { "default": { "type": "simple" }, "default_seach": { "type": "whitespace" } } } }}