es種有兩種查詢模式,一種是像傳遞URL參數(shù)一樣去傳遞查詢語句把鉴,被稱為簡單搜索或查詢字符串(query string)搜索故黑,比如
GET /megacorp/employee/_search //查詢?nèi)繂T工
GET /megacorp/employee/_search?q=last_name:Smith //查詢last_name為Smith的員工
另外一種是通過DSL語句來進行查詢儿咱,被稱為DSL查詢(Query DSL),DSL是Elasticsearch提供的一種豐富且靈活的查詢語言,該語言以json請求體的形式出現(xiàn)场晶,通過restful請求與Elasticsearch進行交互混埠,本文主要講DSL查詢的一些常用規(guī)則,在介紹之前诗轻,我們先簡單插入一個測試用的小例子(假設(shè)我們已經(jīng)有了一個elasticsearch測試環(huán)境且裝好了分詞插件, 如果需要查看如何安裝中文環(huán)境钳宪,可瀏覽我的另一篇文章Elasticsearch中文搜索環(huán)境搭建)。
$curl -XPOST http://localhost:9200/index/doc/1 -d'{"content":"美國留給伊拉克的是個爛攤子嗎","title":"標題","tags":["美國","伊拉克","爛攤子"]}'
$curl -XPOST http://localhost:9200/index/doc/2 -d'{"content":"中國是世界上人口最多的國家","title":"中國","tags":["中國","人口"]}'
$curl -XPOST http://localhost:9200/index/doc/3 -d'{"content":"同一個世界同一個夢想","title":"北京奧運","tags":["和平"]}'
$curl -XPOST http://localhost:9200/index/doc/4 -d'{"content":"杭州是一個美麗的城市,歡迎來到杭州","title":"宣傳","tags":["旅游","城市"]}'
檢查一下我們的數(shù)據(jù)是否導(dǎo)入成功
$curl -XGET http://localhost:9200/index/doc/_search
{"took":1,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":4,"max_score":1.0,"hits":[{"_index":"index","_type":"doc","_id":"2","_score":1.0,"_source":{"content":"中國是世界上人口最多的國家","title":"中國","tags":["中國","人口"]}},{"_index":"index","_type":"doc","_id":"4","_score":1.0,"_source":{"content":"杭州是一個美麗的城市,歡迎來到杭州","title":"宣傳","tags":["旅游","城市"]}},{"_index":"index","_type":"doc","_id":"1","_score":1.0,"_source":{"content":"美國留給伊拉克的是個爛攤子嗎","title":"標題","tags":["美國","伊拉克","爛攤子"]}},{"_index":"index","_type":"doc","_id":"3","_score":1.0,"_source":{"content":"同一個世界同一個夢想","title":"北京奧運","tags":["和平"]}}]}}
ok扳炬,導(dǎo)入成功吏颖,接下來利用這些數(shù)據(jù)逐步介紹各種常用查詢
term查詢
term是代表完全匹配,也就是精確查詢恨樟,搜索前不會再對搜索詞進行分詞侦高,所以我們的搜索詞必須是文檔分詞集合中的一個。比如說我們要找標題為北京奧運的所有文檔
$curl -XGET http://localhost:9200/index/doc/_search?pretty -d
'{
"query":{
"term":{
"title":"北京奧運"
}
}
}'
將會得到如下結(jié)果
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 0.92055845,
"hits": [
{
"_index": "index",
"_type": "doc",
"_id": "3",
"_score": 0.92055845,
"_source": {
"content": "同一個世界同一個夢想",
"title": "北京奧運",
"tags": [
"和平"
]
}
}
]
}
}
搜索title
包含北京
或者奧運
的厌杜,結(jié)果也一樣奉呛,但是如果你搜索詞為京奧
,或者北京奧
這樣的,那么搜索結(jié)果將為空
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"failed" : 0
},
"hits" : {
"total" : 0,
"max_score" : null,
"hits" : [ ]
}
}
這是因為在對文檔建立索引時夯尽,會將北京奧運分詞為北京
瞧壮,奧運
,北京奧運
匙握,只要搜索詞為這三個之一咆槽,都可以將這篇文章搜索出來,而京奧
和北京奧
并不在分詞集合里圈纺,所以無法搜索到該文檔秦忿。
如果對于某個字段,你想精確匹配蛾娶,即搜索什么詞匹配什么詞灯谣,類似sql中的=
操作,比如只能通過北京奧運
搜索到文檔3而不想讓北京
和奧運
也搜索到蛔琅,那么胎许,你可以在建立索引階段指定該字段為"index": "not_analyzed"
,此時,elasticsearch將不會對該字段的值進行分詞操作罗售,只保留全文字索引辜窑。比如本例子中的tags字段,我在建立索引時設(shè)置了"index": "not_analyzed"
, 搜索時,不管是指定tags為美
寨躁,還是國
穆碎,都無法將第一條結(jié)果搜索出來
$curl -XGET http://localhost:9200/index/doc/_search?pretty -d
'{
"query":{
"term":{
"tags":"美"
}
}
}'
搜索結(jié)果:
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"failed" : 0
},
"hits" : {
"total" : 0,
"max_score" : null,
"hits" : [ ]
}
}
而全詞美國
卻可以
$curl -XGET http://localhost:9200/index/doc/_search?pretty -d
'{
"query":{
"term":{
"tags":"美國"
}
}
}'
搜索結(jié)果:
{
"took" : 2,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"failed" : 0
},
"hits" : {
"total" : 1,
"max_score" : 0.30685282,
"hits" : [ {
"_index" : "index",
"_type" : "doc",
"_id" : "1",
"_score" : 0.30685282,
"_source" : {
"content" : "美國留給伊拉克的是個爛攤子嗎",
"title" : "標題",
"tags" : [ "美國", "伊拉克", "爛攤子" ]
}
} ]
}
}
match類查詢
match查詢會先對搜索詞進行分詞,分詞完畢后再逐個對分詞結(jié)果進行匹配,因此相比于term的精確搜索职恳,match是分詞匹配搜索,match搜索還有兩個相似功能的變種所禀,一個是match_phrase谜悟,一個是multi_match,接下來詳細介紹一下
match
前面提到match搜索會先對搜索詞進行分詞北秽,對于最基本的match搜索來說,只要搜索詞的分詞集合中的一個或多個存在于文檔中即可最筒,例如贺氓,當我們搜索中國杭州
,搜索詞會先分詞為中國
和杭州
,只要文檔中包含搜索
和杭州
任意一個詞床蜘,都會被搜索到
$curl -XGET http://localhost:9200/index/doc/_search?pretty -d
'{
"query": {
"match": {
"content": "中國杭州"
}
}
}'
文檔3正文中有杭州辙培,文檔2中有中國,因此搜索結(jié)果有兩個邢锯,文檔3中杭州出現(xiàn)兩次扬蕊,所以排在前面,結(jié)果如下:
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"failed" : 0
},
"hits" : {
"total" : 2,
"max_score" : 0.99999994,
"hits" : [ {
"_index" : "index",
"_type" : "doc",
"_id" : "4",
"_score" : 0.99999994,
"_source" : {
"content" : "杭州是一個美麗的城市,歡迎來到杭州",
"title" : "宣傳",
"tags" : [ "旅游", "城市" ]
}
}, {
"_index" : "index",
"_type" : "doc",
"_id" : "2",
"_score" : 0.8838835,
"_source" : {
"content" : "中國是世界上人口最多的國家",
"title" : "中國",
"tags" : [ "中國", "人口" ]
}
} ]
}
}
同樣的丹擎,我們用match的方式搜索中國世界
尾抑,那么,文檔2(含有中國
和世界
)和文檔3(含有世界
都會被搜索出來)蒂培。如果我們僅僅想搜索中國
和世界
都包含的文檔該怎么辦呢再愈?
其實,對于match搜索护戳,可以按照分詞后的分詞集合的or
或者and
進行匹配翎冲,默認為or
,這也是為什么我們看到前面的搜索都是只要有一個分詞出現(xiàn)在文檔中就會被搜索出來媳荒,同樣的抗悍,如果我們希望是所有分詞都要出現(xiàn),那只要把匹配模式改成and
就行了
curl -XGET http://localhost:9200/index/doc/_search?pretty -d
'{
"query": {
"match": {
"content": {
"query": "中國世界",
"operator": "and"
}
}
}
}'
如上所示钳枕,查詢時將operator設(shè)置為and
缴渊,此時,就只會搜索到既包含中國鱼炒,也包含世界的文檔了(因返回的字段較多疟暖,后面搜索結(jié)果只展示_source中的內(nèi)容)
"_source" : {
"content" : "中國是世界上人口最多的國家",
"title" : "中國",
"tags" : [ "中國", "人口" ]
}
match_phrase
match_phrase為按短語搜索,這個可能先用英文來解釋會直觀一點(中文分詞后其實已經(jīng)是一個一個有具體意思的詞語)田柔。英文中以空格分詞俐巴,因此分詞后是一個個的單詞,當想搜索類似hope so
這樣的短語時硬爆,你或許并不想將一些只含有hope的文檔搜索出來欣舵,也不想將一些類似I hope ×××. So ××
這樣的搜索出來,此時缀磕,就可以用match_phrase缘圈。
match_phrase的搜索方式和match類似劣光,先對搜索詞建立索引,并要求所有分詞必須在文檔中出現(xiàn)(像不像operator為and
的match查詢)糟把,除此之外绢涡,還必須滿足分詞在文檔中出現(xiàn)的順序和搜索詞中一致且各搜索詞之間必須緊鄰,因此match_phrase也可以叫做緊鄰搜索遣疯。
所以雄可,當我們搜美國留給
時
curl -XGET http://localhost:9200/index/doc/_search?pretty -d
'{
"query": {
"match_phrase": {
"content": "美國留給"
}
}
}'
能搜出文檔美國留給伊拉克的是個爛攤子嗎
"_source" : {
"content" : "美國留給伊拉克的是個爛攤子嗎",
"title" : "標題",
"tags" : [ "美國", "伊拉克", "爛攤子" ]
}
但是我們搜索留給美國
或美國伊拉克
時,卻沒有搜索結(jié)果缠犀,因為一個順序不對数苫,一個不是緊鄰(隔著留給
)。
緊鄰對于匹配度要求較高辨液,為了減小精度增加可操作性虐急,引入了slop
參數(shù)。該參數(shù)可以指定相隔多少個詞仍被算作匹配成功滔迈。如下止吁,
curl -XGET http://localhost:9200/index/doc/_search?pretty -d
'{
"query": {
"match_phrase": {
"content": {
"query": "美國伊拉克",
"slop": "1"
}
}
}
}'
當我們將slop
設(shè)置為1時,文檔1已能被搜索到燎悍。
"_source" : {
"content" : "美國留給伊拉克的是個爛攤子嗎",
"title" : "標題",
"tags" : [ "美國", "伊拉克", "爛攤子" ]
}
需要注意的是赏殃,當slop的值過大時(超出文檔總分詞數(shù)),那么分詞數(shù)據(jù)將可以是隨意的间涵,即跟operator為and
的match查詢效果一樣仁热。比如我們查詢
curl -XGET http://localhost:9200/index/doc/_search?pretty -d
'{
"query": {
"match_phrase": {
"content": {
"query": "伊拉克美國",
"slop": "12"
}
}
}
}'
將會得到與上面一樣的結(jié)果
multi_match
當我們想對多個字段進行匹配,其中一個字段包含分詞就被文檔就被搜索到時勾哩,可以用multi_match,這一部分內(nèi)容我們后面再講