Search APIs(2)—— Request Body Search

Source filtering

这个就是控制source字段如何返回,可以禁用,也可以通配符,也可以使用includes和excludes

//禁用 _source 检索设置为 false
GET /_search
{
    "_source": false,
    "query" : {
        "term" : { "user" : "kimchy" }
    }
}
//通配符
GET /_search
{
    "_source": "obj.*",
    "query" : {
        "term" : { "user" : "kimchy" }
    }
}

Fields

stored_fields显式的指定返回的类型,不推荐使用,推荐使用Source filtering

GET /_search
{
    "stored_fields" : ["user", "postDate"],
    "query" : {
        "term" : { "user" : "kimchy" }
    }
}
//只显示type和id
GET /_search
{
    "stored_fields" : [],
    "query" : {
        "term" : { "user" : "kimchy" }
    }
}
//元数据也没有
GET /_search
{
    "stored_fields": "_none_",
    "query" : {
        "term" : { "user" : "kimchy" }
    }
}

Script Fields和Doc value Fields

这个没运行通,不太懂

Post filter 后置过滤

post_filter 可以作为后置过滤器不影响聚合操作去过滤搜索结果。
因为聚合操作是对搜索到的结果进行聚合,所以query操作会对aggs有影响。

post_filter可以代替query操作返回查询结果,但是不影响聚合
比如shirts没有绿色的,即查询color:green为空。如果用query,aggs对这个空的查询结果进行聚合;但是用post_filter,aggs不考虑这个操作的影响

GET /shirts/_search
{
  "aggs": {
    "models": {
      "terms": {
        "field": "model"
      }
    }
  },
  "post_filter": { //这个地方可以使用query对比
    "term": {
      "color": "green"
    }
  }
}

Highlighting 高亮

基本高亮使用:

GET /_search
{
    "query" : {
        "match": { "content": "kimchy" }
    },
    "highlight" : {
        "fields" : {
            "content" : {//设置高亮的字段为content,可以添加一些参数
                "pre_tags" : ["<tag1>"],
                "post_tags" : ["</tag1>"]
            }
        }
    }
}
内置的tag,</em> 作为 post_tags,pre_tags:

<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">

Rescoring 重排序

Rescoring是对返回的前面一些文档进行重排序,而不是所有的返回结果。
每个分片都会进行Rescoring操作,重新对doc进行评分。得分的权重可以通过query_weight和rescore_query_weight两个参数进行设置,默认都是1。
基本使用:

POST /_search
{
   "query" : {
      "match" : {
         "message" : {
            "operator" : "or",
            "query" : "the quick brown"
         }
      }
   },
   "rescore" : {
      "window_size" : 50,
      "query" : {
         "rescore_query" : {
            "match_phrase" : {
               "message" : {
                  "query" : "the quick brown",
                  "slop" : 2
               }
            }
         },
         "query_weight" : 0.7,
         "rescore_query_weight" : 1.2
      }
   }
}

Search Type

进行分布式搜索时,由于分片的存在,每个分片先分散查询,然后把结果聚集在一起,在这个过程存在多种执行方式。
第一个问题:考虑的是每个分片取多少个,比如我们要10个最相关的结果,有3个分片,每个分片取前10个,这30个再取前10个
第二个问题:每个分片就是一个lucene索引独立存在,每个分片有自己的倒排索引,所以我们如果想要知道准确的结果,应该让所有term的frequency和其他的信息放在一起算出全局的tf,然后进行查询。
第三个问题:如果返回的结果非常大,到后面其实得分已经没那么重要,所以当使用scroll时,没必要按照分值高低排序,可以直接按照doc的id进行排序返回。
可以通过下面两个控制:query_then_fetch和dfs_query_then_fetch,两者的区别在于第二个问题的解决,前者就是第一个问题说的那样,dfs会重新计算分布在各个分片的词频,计算更准确,其他也是和第一个问题说的那样。

Scroll 死游标

当结果特别多的时候,需要滚动scroll来遍历搜索结果。这就像mysql数据库或者mongod中的游标cursor作用一样。
Scroll有一个属性是存活的时间,这个要再初始搜索就要设置,像下面的1m就是一分钟没人用,这个生成的scroll_id就不能用了,这样:

GET /aminer/aminer/_search?scroll=1m
{
  "size": 20,
  "query": {
    "match": {
      "year": 1996
    }
  }
}

再次搜索不要指定index和type,这个在初始搜索里指定,scroll需要重新指定,这里重新开始能活1分钟。

POST /_search/scroll
{
  "scroll" : "1m",
  "scroll_id": "DnF1ZXJ5VGhlbkZldGNoAwAAAAAAQBWyFlN5bEtKWjh2U1JXZ0QybTVMV0FFR1EAAAAAAEAVtBZTeWxLSlo4dlNSV2dEMm01TFdBRUdRAAAAAABAFbMWU3lsS0paOHZTUldnRDJtNUxXQUVHUQ=="
}

可以删除scroll_id

DELETE /_search/scroll
{
    "scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAD4WYm9laVYtZndUQlNsdDcwakFMNjU1QQ=="
}

Preference

preference可以控制搜索的时候使用哪些分片的偏好,默认情况下ES是随机选择分片的副本进行搜索。可以像下面那样指定:

GET /_search?preference=xyzabc123
{
    "query": {
        "match": {
            "title": "elasticsearch"
        }
    }
}

Explain

解释分是怎么算出来的

GET /_search
{
    "explain": true,
    "query" : {
        "term" : { "user" : "kimchy" }
    }
}

Version

返回每个结果的版本号

GET /_search
{
    "version": true,
    "query" : {
        "term" : { "user" : "kimchy" }
    }
}

Index Boost

允许在跨多个索引搜索时为每个索引配置不同的提升级别。 当来自一个索引的命中数大于来自另一个索引的命中数时(比如根据用户id确定索引位置然后返回微博的每个用户的社交关系),这是非常方便的。

GET /_search
{
    "indices_boost" : [
        { "alias1" : 1.4 },
        { "index*" : 1.3 }
    ]
}

min_score

排除 score 小于 minscore 中指定的最小值的文档:

GET /_search
{
    "min_score": 0.5,
    "query" : {
        "term" : { "user" : "kimchy" }
    }
}

Named Queries

每个filter和查询可以在其顶级定义中一个 _name 属性。

GET /_search
{
    "query": {
        "bool" : {
            "should" : [
                {"match" : { "name.first" : {"query" : "shay", "_name" : "first"} }},
                {"match" : { "name.last" : {"query" : "banon", "_name" : "last"} }}
            ],
            "filter" : {
                "terms" : {
                    "name.last" : ["banon", "kimchy"],
                    "_name" : "test"
                }
            }
        }
    }
}

Inner hits

parent-join和nested会出现内部被匹配,此时可以通过下面的设置具体找到内部的哪个地方被命中

POST test/_search
{
  "query": {
    "nested": {
      "path": "comments",
      "query": {
        "match": {"comments.number" : 2}
      },
      "inner_hits": {} //这一句显示comments内部具体命中的情况
    }
  }
}

Field Collapsing 字段折叠

允许通过字段对结果进行折叠。折叠操作是通过选择每个折叠键的顶部文档来实现。例如下面的query获取每个user的最佳tweet并且根据他们的likes数量排序。

GET /twitter/_search
{
    "query": {
        "match": {
            "message": "elasticsearch"
        }
    },
    "collapse" : {
        "field" : "user" //折叠
    },
    "sort": ["likes"], //排序
    "from": 10 //从10开始
}

也支持inner_hits的折叠

GET /twitter/_search
{
    "query": {
        "match": {
            "message": "elasticsearch"
        }
    },
    "collapse" : {
        "field" : "user", 
        "inner_hits": [
            {
                "name": "most_liked",  
                "size": 3,
                "sort": ["likes"]
            },
            {
                "name": "most_recent", 
                "size": 3,
                "sort": [{ "date": "asc" }]
            }
        ]
    },
    "sort": ["likes"]
}

Search After 活游标

搜索结果可以使用from和size实现,但如果很深效果不好。并且index默认使用index.max_result_window对索引进行保护,最多一次返回10000个。
对于过多的搜索结果可以使用scroll实现,但是必须一点一点滚动出来,不能处理用户的实时需求。 search_after 参数通过提供活动光标来规避此问题。 这个想法是使用前一页的结果来帮助检索下一页。
当使用search_after参数时,from的值必须被设为0或者-1
这个和scroll很像,首先有第一次的拉取,像下面这样的sort排序的

GET twitter/_search
{
    "size": 10,
    "query": {
        "match" : {
            "title" : "elasticsearch"
        }
    },
    "sort": [
        {"date": "asc"},
        {"_id": "desc"}//sort参数里必须至少使用一个唯一的字段来进行排序,推荐的做法是使用 _id 字段
    ]
}

然后可以使用search_after了,search_after的参数可以是上一次的排序结果中最后一个的值:

GET twitter/_search
{
    "size": 10,
    "query": {
        "match" : {
            "title" : "elasticsearch"
        }
    },
    "search_after": [1463538857, "654323"],//date和_id
    "sort": [
        {"date": "asc"},
        {"_id": "desc"}
    ]
}

search_after 不是为了解决能跳转到随机的任何一个分页而设计的,而是为了并行的拉取大量数据。它和 scroll 接口的方式类似,但search_after 是无状态的,而且能用于用户的实时搜索。

发表评论

电子邮件地址不会被公开。