一、需要解决的问题

有的时候我们需要同时执行多个查询,并且需要得到每个单独查询的搜索结果,elasticsearch提供了multi search此需求的支持;

二、elasticsearch multi search简介

elasticsearch提供了multi search api来支持一个请求执行多个查询;

multi search api的请求体使用换行分割的JSON格式;

header\n
body\n
header\n
body\n

multi search返回的结果是responses数组,每个查询对应一个数组元素;每个数组元素都有一个status字段指示查询是否执行成功,如果执行失败则error字段返回错误信息;

每个查询可以通过自己的header设置查询执行的index,也可以是空的JSON对象,这是在URL中指定的index执行查询;

三、数据准备

index以下四个文档

PUT /multi_test/_doc/1
{
	"name":"Google Chrome"
}


PUT /multi_test/_doc/2
{
	"name":"NotePad"
}

PUT /multi_test/_doc/3
{
	"name":"Word"
}

PUT /multi_test/_doc/4
{
	"name":"PyCharm"
}

查询查看已经索引的数据

GET /multi_test/_search

{
    "took":0,
    "timed_out":false,
    "_shards":{
        "total":5,
        "successful":5,
        "skipped":0,
        "failed":0
    },
    "hits":{
        "total":4,
        "max_score":1,
        "hits":[
            {
                "_index":"multi_test",
                "_type":"_doc",
                "_id":"2",
                "_score":1,
                "_source":{
                    "name":"NotePad"
                }
            },
            {
                "_index":"multi_test",
                "_type":"_doc",
                "_id":"4",
                "_score":1,
                "_source":{
                    "name":"PyCharm"
                }
            },
            {
                "_index":"multi_test",
                "_type":"_doc",
                "_id":"1",
                "_score":1,
                "_source":{
                    "name":"Google Chrome"
                }
            },
            {
                "_index":"multi_test",
                "_type":"_doc",
                "_id":"3",
                "_score":1,
                "_source":{
                    "name":"Word"
                }
            }
        ]
    }
}

四、查询测试

我们构造以下四个查询同时执行

POST /multi_test/_msearch

{}
{"query":{"match":{"name":"google"}}}
{}
{"query":{"match":{"name":"nohit"}}}
{}
{"query":{"match":{"name":"word"}}}
{}
{"query":{"bool":{"should":[{"match":{"name":"word"}}, {"match":{"name":"pycharm"}}]}}}

我们可以看到不管查询是否命中结果,都会有一个responses数组元素对应;同时responses数组元素的顺序与查询是一 一对应的;

{
    "responses":[
        {
            "took":0,
            "timed_out":false,
            "_shards":{
                "total":5,
                "successful":5,
                "skipped":0,
                "failed":0
            },
            "hits":{
                "total":1,
                "max_score":0.2876821,
                "hits":[
                    {
                        "_index":"multi_test",
                        "_type":"_doc",
                        "_id":"1",
                        "_score":0.2876821,
                        "_source":{
                            "name":"Google Chrome"
                        }
                    }
                ]
            },
            "status":200
        },
        {
            "took":0,
            "timed_out":false,
            "_shards":{
                "total":5,
                "successful":5,
                "skipped":0,
                "failed":0
            },
            "hits":{
                "total":0,
                "max_score":null,
                "hits":[

                ]
            },
            "status":200
        },
        {
            "took":0,
            "timed_out":false,
            "_shards":{
                "total":5,
                "successful":5,
                "skipped":0,
                "failed":0
            },
            "hits":{
                "total":1,
                "max_score":0.2876821,
                "hits":[
                    {
                        "_index":"multi_test",
                        "_type":"_doc",
                        "_id":"3",
                        "_score":0.2876821,
                        "_source":{
                            "name":"Word"
                        }
                    }
                ]
            },
            "status":200
        },
        {
            "took":0,
            "timed_out":false,
            "_shards":{
                "total":5,
                "successful":5,
                "skipped":0,
                "failed":0
            },
            "hits":{
                "total":2,
                "max_score":0.6931472,
                "hits":[
                    {
                        "_index":"multi_test",
                        "_type":"_doc",
                        "_id":"4",
                        "_score":0.6931472,
                        "_source":{
                            "name":"PyCharm"
                        }
                    },
                    {
                        "_index":"multi_test",
                        "_type":"_doc",
                        "_id":"3",
                        "_score":0.2876821,
                        "_source":{
                            "name":"Word"
                        }
                    }
                ]
            },
            "status":200
        }
    ]
}

五、multi search对search template的支持

multi search api也支持search template;

muti search内联search template查询

POST /multi_test/_msearch/template
{}
{ "source" : "{ \"query\": { \"match\": { \"name\" : \"{{name}}\" } } } }", "params": { "name": "google" } }
{}
{ "source" : "{ \"query\": { \"match_{{template}}\": {} } }", "params": { "template": "all" } }

查询结果为

{
    "responses":[
        {
            "took":0,
            "timed_out":false,
            "_shards":{
                "total":5,
                "successful":5,
                "skipped":0,
                "failed":0
            },
            "hits":{
                "total":1,
                "max_score":0.2876821,
                "hits":[
                    {
                        "_index":"multi_test",
                        "_type":"_doc",
                        "_id":"1",
                        "_score":0.2876821,
                        "_source":{
                            "name":"Google Chrome"
                        }
                    }
                ]
            }
        },
        {
            "took":8,
            "timed_out":false,
            "_shards":{
                "total":5,
                "successful":5,
                "skipped":0,
                "failed":0
            },
            "hits":{
                "total":4,
                "max_score":1,
                "hits":[
                    {
                        "_index":"multi_test",
                        "_type":"_doc",
                        "_id":"2",
                        "_score":1,
                        "_source":{
                            "name":"NotePad"
                        }
                    },
                    {
                        "_index":"multi_test",
                        "_type":"_doc",
                        "_id":"4",
                        "_score":1,
                        "_source":{
                            "name":"PyCharm"
                        }
                    },
                    {
                        "_index":"multi_test",
                        "_type":"_doc",
                        "_id":"1",
                        "_score":1,
                        "_source":{
                            "name":"Google Chrome"
                        }
                    },
                    {
                        "_index":"multi_test",
                        "_type":"_doc",
                        "_id":"3",
                        "_score":1,
                        "_source":{
                            "name":"Word"
                        }
                    }
                ]
            }
        }
    ]
}

也可以直接新建search template

POST /_scripts/multi_test_name_template/

{
    "script":{
        "lang":"mustache",
        "source":{
            "query":{
                "bool":{
                    "should":[
                        {
                            "match":{
                                "name":"{{name}}"
                            }
                        },
                        {
                            "wildcard":{
                                "name":"*{{name}}*"
                            }
                        }
                    ]
                }
            }
        }
    }
}

使用新建的search template进行搜索

POST /multi_test/_msearch/template
{}
{ "id": "multi_test_name_template", "params": { "name": "oo" } }
{}
{ "id": "multi_test_name_template", "params": { "name": "notepad" } }

搜索结果如下

{
    "responses":[
        {
            "took":1,
            "timed_out":false,
            "_shards":{
                "total":5,
                "successful":5,
                "skipped":0,
                "failed":0
            },
            "hits":{
                "total":1,
                "max_score":1,
                "hits":[
                    {
                        "_index":"multi_test",
                        "_type":"_doc",
                        "_id":"1",
                        "_score":1,
                        "_source":{
                            "name":"Google Chrome"
                        }
                    }
                ]
            }
        },
        {
            "took":1,
            "timed_out":false,
            "_shards":{
                "total":5,
                "successful":5,
                "skipped":0,
                "failed":0
            },
            "hits":{
                "total":1,
                "max_score":1.6931472,
                "hits":[
                    {
                        "_index":"multi_test",
                        "_type":"_doc",
                        "_id":"2",
                        "_score":1.6931472,
                        "_source":{
                            "name":"NotePad"
                        }
                    }
                ]
            }
        }
    ]
}

在search template中使用嵌套字段作为参数

POST /multi_test/_msearch/template
{}
{ "source" : "{ \"query\": { \"match\": { \"name\" : \"{{person.name}}\" } } } }", "params": { "person":{"name": "google"} } }

搜索结果如下

{
    "responses":[
        {
            "took":3,
            "timed_out":false,
            "_shards":{
                "total":5,
                "successful":5,
                "skipped":0,
                "failed":0
            },
            "hits":{
                "total":1,
                "max_score":0.2876821,
                "hits":[
                    {
                        "_index":"multi_test",
                        "_type":"_doc",
                        "_id":"1",
                        "_score":0.2876821,
                        "_source":{
                            "name":"Google Chrome"
                        }
                    }
                ]
            }
        }
    ]
}
01-05 18:16