elasticsearch之單請求多查詢

無風聽海發表於2023-01-05

一、需要解決的問題

有的時候我們需要同時執行多個查詢,並且需要得到每個單獨查詢的搜尋結果,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"
                        }
                    }
                ]
            }
        }
    ]
}

相關文章