Elasticsearch系列(8)Search之折叠、过滤及高

2020-09-08  本文已影响0人  正义的杰克船长

1. 折叠

使用collapse参数根据字段折叠搜索结果。折叠会合并指定折叠字段内容相同的数据,并选择排序文档结果集中第一个文档返回。例如,按照user.id折叠搜索结果,示例如下:

PUT my_index_01
{
  "mappings": {
    "properties": {
      "message": {
        "type": "text"
      },
      "user.id": {
        "type": "long"
      },
      "user.name": {
        "type": "keyword"
      },
      "http.response.bytes": {
        "type": "integer"
      },
      "@timestamp": {
        "type": "date"
      }
    }
  }
}
PUT my_index_01/_doc/1
{
  "message": "GET /search",
  "user": {
    "id": 10001,
    "name": "johnny"
  },
  "@timestamp": "2015-01-01",
  "http.response.bytes": 10
}
PUT my_index_01/_doc/2
{
  "message": "GET /_doc",
  "user": {
    "id": 10001,
    "name": "johnny"
  },
  "@timestamp": "2015-01-02",
  "http.response.bytes": 8
}
GET /my_index_01/_search
{
  "query": {
    "match": {
      "message": "GET /search"
    }
  },
  "collapse": {
    "field": "user.id"                
  }
}

返回折叠结果

{
  "took" : 4,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [
      {
        "_index" : "my_index_01",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.8754687,
        "_source" : {
          "message" : "GET /search",
          "user" : {
            "id" : 10001,
            "name" : "johnny"
          }
        },
        "fields" : {
          "user.id" : [
            10001
          ]
        }
      }
    ]
  }
}

扩展折叠结果

对于每个折叠后的命中结果集,可以再次请求其多个inner_hits,在展示折叠命中结果集多种表示形式时有用,通过参数collapse. inner_hits可以做到,示例如下:

GET /my_index_01/_search
{
  "query": {
    "match": {
      "message": "GET /search"
    }
  },
  "collapse": {
    "field": "user.id",                      
    "inner_hits": [
      {
        "name": "largest_responses",         //1
        "size": 1,
        "sort": [ {"http.response.bytes":"desc"} ]
      },
      {
        "name": "most_recent",             //2  
        "size": 1,
        "sort": [ { "@timestamp": "asc" } ]
      }
    ]
  },
  "sort": [ "http.response.bytes" ]
}

注释1:inner_hits结果集名称为largest_responses,基于折叠后搜索结果,按照http.response.bytes倒叙排列,并获取size指定条数的数据。
注释2:inner_hits结果集名称为most_recent,基于折叠后搜索结果,按照@timestamp顺序排列,并获取size指定条数的数据。

二级折叠

inner_hits也支持再次折叠,通过参数collapse. inner_hits. collapse可以折叠inner_hits结果集。示例如下:

GET /my_index_01/_search
{
  "query": {
    "match": {
      "message": "GET /search"
    }
  },
  "collapse": {
    "field": "user.id",                      
    "inner_hits": [
      {
        "name": "largest_responses",         
        "size": 2,
        "collapse": { "field": "user.name" },
        "sort": [ {"http.response.bytes":"desc"} ]
      }
    ]
  }
}

2. 过滤

可以使用以下两种方式来过滤搜索结果:

(1)使用带有filter子句的boolean query(布尔查询)。搜索请求中的搜索命中集和聚合都可使用boolean filters(boolean过滤器),即聚合会基于boolean query过滤。
(2)使用search API(搜索API)中的post_filter参数。搜索请求仅将post过滤器应用于搜索命中集,不会应用于聚合。可以使用post过滤器基于更广泛的结果集来进行计算聚合,然后进一步缩小结果。

可以在post过滤器之后重新计算得分,以提高相关性和结果重排。

Post过滤器

使用post_filter参数来过滤搜索结果,但它不影响聚合结果。例如,搜索华为品牌,红色类型的手机,并且希望聚合所有华为手机,操作示例如下:

PUT /my_index_phone
{
  "mappings": {
    "properties": {
      "brand": { "type": "keyword" },
      "color": { "type": "keyword" },
      "model": { "type": "keyword" }
    }
  }
}
PUT /my_index_phone/_doc/1?refresh
{"brand":"huawei","color":"red","model":"mate40"}
PUT /my_index_phone/_doc/2?refresh
{"brand":"huawei","color":"red","model":"p30"}
PUT /my_index_phone/_doc/3?refresh
{"brand":"huawei","color":"white","model":"p30"}

GET /my_index_phone/_search
{
  "query": {
    "bool": {
      "filter": { //1
        "term": { "brand": "huawei" }  
      }
    }
  },
  "aggs": {
    "colors": { //2
      "terms": { "field": "color" } 
    },
    "color_red": { //3
      "filter": {
        "term": { "color": "red" } 
      },
      "aggs": {
        "models": {
          "terms": { "field": "model" } 
        }
      }
    }
  },
  "post_filter": {  //4
    "term": { "color": "red" }
  }
}

注释1:boolean查询过滤 品牌为华为的手机,此查询影响聚合操作,会影响操作2和3。
注释2:以color字段聚合,也就是按颜色归类聚合华为手机,有红色和白色两种,聚合结果返回有key=red和key=white两个桶(buckets)。
注释3:先按照color:red过滤,然后再按照model字段聚合,即查询红色的、华为品牌的手机,并且按照model分类聚合,聚合结果返回key=mate40和key=p30两个桶(buckets)。
注释4:搜索查询只查询颜色为红色的,Post过滤器应用于搜索查询,不会影响聚合操作,即不影响操作2和3。

重新计分器

查询重新计分器(rescorer)只对query和post_filter阶段返回的Top-K结果执行第二个查询。
通过window_size参数控制每个分片上被检查的文档数量,默认值是10。
默认情况下,原始查询和rescore查询的分数被线性组合(可配置),从而为每个文档生成最终的_score,原始查询和rescore查询的相对重要性可以分别用query_weight参数和rescore_query_weight参数来控制,两者都默认为1。

POST /my_index_phone/_search
{
   "query" : {
      "match" : {
         "model" : {
            "operator" : "or",
            "query" : "p30"
         }
      }
   },
   "rescore" : [ {
      "window_size" : 100,
      "query" : {
         "rescore_query" : { // 1
            "match_phrase" : {
               "color" : {
                  "query" : "white",
                  "slop" : 2
               }
            }
         },
         "query_weight" : 0.7, 
         "rescore_query_weight" : 1.2 //2
      }
   }]
}

注释1:rescore查询颜色为白色的短语查询并计算得分,该得分线性组合原始得分来决定最终得分。
注释2:rescore查询相关性权重设置。

通过参数score_mode配置得分组合的方式,score_mode配置值如下:

并且Elasticsearch支持按顺序多个rescore查询,示例如下:

POST /my_index_phone/_search
{
   "query" : {
      "match" : {
         "brand" : {
            "operator" : "or",
            "query" : "huawei"
         }
      }
   },
   "rescore" : [ {
        "window_size" : 100,
        "query" : {
           "rescore_query" : {
              "match_phrase" : {
                 "color" : {
                    "query" : "red",
                    "slop" : 2
                 }
              }
           },
           "query_weight" : 1,
           "rescore_query_weight" : 2
        }
     },
      {
        "window_size" : 10,
        "query" : {
           "score_mode": "multiply",
           "rescore_query" : {
              "function_score" : {
                 "script_score": {
                    "script": {
                      "source": "Math.log10(_score + 2)"
                    }
                 }
              }
           }
        }
     }
   ]
}

3. 高亮

高亮器(Highlighters)能够将搜索结果中的一个或多个字段加上代码片段以突出显示。当要请求高亮显示时,Elasticsearch响应会为每个搜索命中集包含一个额外的高亮元素,其中包括高亮显示的字段和高亮显示的片段。

GET /my_index_phone/_search
{
  "query": {
    "match": { "model": "p30" }
  },
  "highlight": {
    "fields": {
      "model": {}
    }
  }
}

返回结果片段:

 ...
{
    "_index" : "my_index_phone",
    "_type" : "_doc",
    "_id" : "3",
    "_score" : 0.4700036,
    "_source" : {
      "brand" : "huawei",
      "color" : "white",
      "model" : "p30"
    },
    "highlight" : {
      "model" : [
        "<em>p30</em>" //1
      ]
    }
}
...

注释1:高亮显示,默认加上<em></em>标签。

高亮器类型

高亮器类型有三种:unified,plain和fvh。可以通过type参数来修改每个字段的高亮器类型,Elasticsearch高亮器默认unified。

高亮器设置

高亮器设置(Highlighting settings)可以在全局级别设置,并在字段级别覆盖。具体参数设置有以下:

boundary_chars

包含每个边界字符的字符串。默认为.,!? \t\n。

boundary_max_scan

扫描边界字符的范围。默认为20。

boundary_scanner

指定如何切分突出显示的片段(fragments),有三个设置值:chars、sentence或word。仅适用于unified和fvh高亮器。unified高亮器默认该设置值为sentence,fvh高亮器默认该设置值为chars。

boundary_scanner_locale

控制用于搜索句子和单词边界的语言环境。这个参数采用语言标记的形式,例如。“en-us”、“-fr”、“ja-JP”。更多信息可以在 Locale Language Tag
文档中找到。默认值是local.root。

encoder

指示代码段是否应该用HTML编码:default(无编码)或html (HTML-转义代码段文本,然后插入高亮显示标记)。

fields

指定要检索高亮显示的字段。可以使用通配符来指定字段。例如,可以指定content*来高亮显示所有以content开头的text和keyword字段。示例如下:

GET my_index_01/_search
{
  "query": {
    "match": {
      "content": "红豆生南国。"
    }
  },
   "highlight": {
    "fields": {
      "content*": {"type": "plain"}
    }
  }
}
force_source

即使字段是单独存储的,也要基于字段_source高亮显示。默认值为false。

fragmenter

指定文本应该如何在高亮显示片段中拆分:simplespan。仅对plain highlighter有效。默认值为span。

fragment_offset

控制开始高亮显示的页边距。仅对fvh高亮器有效。

fragment_size

以字符为单位高亮显示的片段大小。默认为100。

highlight_query

高亮显示搜索查询以外的其他查询的匹配项。这在使用rescore查询时特别有用,因为默认情况下高亮显示不会考虑rescore查询。

matched_fields

如果没有要高亮显示的匹配片段,则希望从字段的开始位置返回的文本数量。默认值为0(不返回任何内容)。

number_of_fragments

返回的最大片段数。如果片段数设置为0,则不返回片段。相反,整个字段内容将高亮显示并返回。当需要高亮显示短文本(如标题或地址)时,这很方便,但不需要分割。如果number_of_fragments为0,则会忽略fragment_size。默认为5。

order

当设置值为score时,根据得分对高亮显示的片段进行排序。默认情况下(默认值none),片段将按照它们在字段中出现的顺序输出。

phrase_limit

控制文档中要考虑的匹配短语的数量。防止fvh高亮器分析太多的短语和消耗太多的内存。在使用matched_fields时,将考虑每个匹配字段的phrase_limit。提高限制值会增加查询时间并消耗更多内存。只支持fvh高亮器。默认为256。

pre_tags

与post_tags一起使用,定义用于高亮显示文本的HTML标记。默认情况下,高亮显示的文本被包裹在<em>和</em>标签中。指定为字符串数组。

post_tags

与pre_tags一起使用,定义用于高亮显示文本的HTML标记。默认情况下,高亮显示的文本被包装在<em>和</em>标签中。指定为字符串数组。操作示例如下:

GET my_index_01/_search
{
  "query": {
    "match": {
      "content": "红豆生南国"
    }
  },
   "highlight": {
    "fields": {
      "content*": {"type": "plain"}
    },
    "pre_tags": ["<em>"],
    "post_tags": ["</em>"]
  }
}
require_field_match

默认情况下(默认值为true),只有包含查询匹配的字段才会高亮显示。如果将require_field_match设置为false,那么会高亮显示所有字段。

tags_schema

通过使用内置标签模式(tags schema)设置样式。该模式定义了以下pre_tags的样式并将post_tags定义为</em>。

<em class="hlt1">, <em class="hlt2">, <em class="hlt3">,
<em class="hlt4">, <em class="hlt5">, <em class="hlt6">,
<em class="hlt7">, <em class="hlt8">, <em class="hlt9">,
<em class="hlt10">
type

使用的高亮器类型:unified,plain和fvh。

高亮样例

先创建索引并索引数据。

PUT /my_index_01
{
  "mappings": {
    "properties": {
       "content": {
        "type": "text"
      },
      "name":{
        "type": "text"
      }
    }
  }
}
POST /my_index_01/_create/1
{
  "content": "Quick Brown Fox,Quick White Fox, Quick gray Fox",
  "name": "Fox"
}
高亮所有字段

通过require_field_match参数设置false来高亮所有字段,示例如下:

GET my_index_01/_search
{
  "query": {
    "match": {
      "name": "Fox"
    }
  },
   "highlight": {
    "require_field_match": false,
    "fields": {
      "name": { },
      "content": {}
    }
  }
}
配置高亮标签样式

通过tags_schema参数设置标签样式,示例如下:

GET my_index_01/_search
{
  "query": {
    "match": {
      "name": "Fox"
    }
  },
   "highlight": {
    "tags_schema" : "styled",
    "fields": {
      "name": { }
    }
  }
}
控制高亮片段

每个高亮显示的字段可以控制其高亮显示的片段的大小(默认为100),以及返回的最大片段数(默认为5)。示例如下:

GET my_index_01/_search
{
  "query": {
    "match": {
      "content": "Fox"
    }
  },
   "highlight": {
    "fields": {
      "content": {"fragment_size" : 15, "number_of_fragments" : 2}
    }
  }
}
为plain高亮器指定fragmenter

通过fragmenter参数和type参数设置。示例如下:

GET my_index_01/_search
{
  "query": {
    "match_phrase": { "content": "Brown Fox" }
  },
  "highlight": {
    "fields": {
      "content": {
        "type": "plain",
        "fragment_size": 15,
        "number_of_fragments": 2,
        "fragmenter": "simple"
      }
    }
  }
}
上一篇下一篇

猜你喜欢

热点阅读