寫在前面

Elasticsearch(以下簡稱ES)有個copy_to
的功能,之前在一個項目中用到,感覺像是發現了一個神器。這個東西并不是像有些人說的是個語法糖。它用好了不但能提高檢索的效率,還可以簡化查詢語句。
基本用法介紹
直接上示例。
先看看mapping,
PUT?my_index
{
??"mappings":?{
????"properties":?{
??????"first_name":?{
????????"type":?"text",
????????"copy_to":?"full_name"?
??????},
??????"last_name":?{
????????"type":?"text",
????????"copy_to":?"full_name"?
??????},
??????"full_name":?{
????????"type":?"text"
??????}
????}
??}
}
first_name和last_name都指定了copy_to
,表示他們這兩個字段的值都會復制到full_name上。寫入兩條文檔看看,
PUT?my_index/_doc/1
{
??"first_name":?"John",
??"last_name":?"Smith"
}
PUT?my_index/_doc/2
{
??"first_name":?"Tom",
??"last_name":?"Cruise"
}
然后我們在查詢的時候,就可以指定從full_name這個字段查詢了,
GET?my_index/_search
{
??"query":?{
????"match":?{
??????"full_name":?{?
????????"query":?"John?Smith",
????????"operator":?"and"
??????}
????}
??}
}
查詢結果如下:
"hits"?:?{
????"total"?:?{
??????"value"?:?1,
??????"relation"?:?"eq"
????},
????"max_score"?:?1.3862944,
????"hits"?:?[
??????{
????????"_index"?:?"my_index",
????????"_type"?:?"_doc",
????????"_id"?:?"1",
????????"_score"?:?1.3862944,
????????"_source"?:?{
??????????"first_name"?:?"John",
??????????"last_name"?:?"Smith"
????????}
??????}
????]
??}
如果沒有使用copy_to的話,我們需要指定兩個字段查詢,類似如下的語句:
GET?my_index/_search
{
??"query":?{
????"bool":?{
??????"must":?[
????????{"match":?{
??????????"first_name":?"John"
????????}},
????????{"match":?{
??????????"last_name":?"Smith"
????????}}
??????]
????}
??}
}
兩種方式查詢的結果是一樣的。
進階
聊完了基本用法,來看看一些高級的功能。假如說我們想獲取full_name的內容,有些業務場景下,我們會需要返回這個字段,怎么辦呢?其實很簡單,如下所示,我們在設置mapping的時候加上store:true
即可。
PUT?my_index
{
??"mappings":?{
????"properties":?{
??????"first_name":?{
????????"type":?"text",
????????"copy_to":?"full_name"?
??????},
??????"last_name":?{
????????"type":?"text",
????????"copy_to":?"full_name"?
??????},
??????"full_name":?{
????????"type":?"text",
????????"store":?true
??????}
????}
??}
}
然后再寫入文檔,我們可以通過下面的語句查詢到full_name的內容。
GET?my_index/_doc/1?stored_fields=full_name
得的結果是:
{
??"_index"?:?"my_index",
??"_type"?:?"_doc",
??"_id"?:?"1",
??"_version"?:?1,
??"_seq_no"?:?0,
??"_primary_term"?:?1,
??"found"?:?true,
??"fields"?:?{
????"full_name"?:?[
??????"John",
??????"Smith"
????]
??}
}
如果你沒有指定store
為true,查詢的結果是這樣的:
{
??"_index"?:?"my_index",
??"_type"?:?"_doc",
??"_id"?:?"1",
??"_version"?:?1,
??"_seq_no"?:?0,
??"_primary_term"?:?1,
??"found"?:?true
}
再來看另外一個問題。把上面的mapping改一下,text改為keyword,如下:
PUT?my_index
{
??"mappings":?{
????"properties":?{
??????"first_name":?{
????????"type":?"keyword",
????????"copy_to":?"full_name"?
??????},
??????"last_name":?{
????????"type":?"keyword",
????????"copy_to":?"full_name"?
??????},
??????"full_name":?{
????????"type":?"keyword",
????????"store":?true
??????}
????}
??}
}
然后還是寫入上面示例的兩條數據。當我們用通用的查詢語句查詢時發現搜索不到結果了,這是為啥呢?
我這里先給出解決方案,但是不解釋原理,有興趣的可以思考下。
用下面兩個查詢語句都可以查詢到結果,你覺得是什么原因?
GET?my_index/_search
{
??"query":?{
????"bool":?{
??????"must":?[
????????{"term":?{
??????????"first_name":?{
????????????"value":?"John"
??????????}
????????}},
????????{"term":?{
??????????"last_name":?{
????????????"value":?"Smith"
??????????}
????????}}
??????]
????}
??}
}
GET?my_index/_search
{
??"query":?{
????"terms":?{
??????"full_name":?[
????????"John",
????????"Smith"
??????]
????}
??}
}