写在前面
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"
]
}
}
}