以下都是在linux的shell环境中的命令。
curl -XPUT 11.11.11.11:30000/test_index/product/1 -d '{"brand_name" : "华为","product_name" : "华为Mate10"}'
我们可以看到,上述命令包含如下四部分的信息:
正确返回结果:
{
"_index": "test_index",
"_type": "product",
"_id": "1",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 2,
"failed": 0
},
"created": true
}
注意:在ES中,我们不需要专门单独创建索引、类型,而是可以直接向索引、类型中插入数据,如果索引、类型当时不存在,它们会被自动的创建。同理,如果插入数据时,id已经存在,则会自动重写文档,即变成了更新操作。具体请见第3节“更新数据”。
curl -XGET 11.11.11.11:30000/test_index/product/1
其中,在url中我们指定了检索的索引、类型和ID。
返回结果:
{
"_index": "test_index",
"_type": "product",
"_id": "1",
"_version": 1,
"found": true,
"_source": {
"brand_name": "华为",
"product_name": "华为Mate10"
}
}
返回结果是一个json,实际文档内容放在_source
中。
curl -XGET 11.11.11.11:30000/test_index/product/_search
这个命令会返回test_index索引、product类型下的所有文档:
{
"took": 46,
"timed_out": false,
"_shards": {
"total": 4,
"successful": 4,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 1.0,
"hits": [{
"_index": "test_index",
"_type": "product",
"_id": "1",
"_score": 1.0,
"_source": {
"brand_name": "华为",
"product_name": "华为Mate10"
}
}, {
"_index": "test_index",
"_type": "product",
"_id": "2",
"_score": 1.0,
"_source": {
"brand_name": "Apple",
"product_name": "iphone6s"
}
}]
}
}
文档内容在 hits.hits
里的每个 _source
中。
默认情况下,搜索会返回前10个结果。
curl -XGET 11.11.11.11:30000/test_index/product/_search?q=brand_name:Apple
这个命令查询brand_name=Apple的文档,结果为:
{
"took": 4,
"timed_out": false,
"_shards": {
"total": 4,
"successful": 4,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 0.80259144,
"hits": [{
"_index": "test_index",
"_type": "product",
"_id": "2",
"_score": 0.80259144,
"_source": {
"brand_name": "Apple",
"product_name": "iphone6s"
}
}]
}
}
其中,_score
为 Lucene 对每个文档的评分,主要依据 TF-IDF 来评分。
除了在url中添加简单的查询条件外,ES还提供了强大的查询语言(DSL),它可以允许我们进行更加强大、复杂的查询。
DSL以JSON请求体的形式使用,例如上面的brand_name=Apple的例子,可以使用如下DSL来表示:
curl -XGET 11.11.11.11:30000/test_index/product/_search -d '{"query":{"match":{"brand_name":"Apple"}}}'
结果除了took
,其他内容均与2.2.2中的结果相同(took
指的是Elasticsearch执行这个搜索的耗时,以毫秒为单位).
注意:
1、match 并不是准确检索,而是不完全匹配,只要匹配上参数中的任何一个分词,都会返回。比如以下命令也会返回brand_name=Apple的结果(只展示-d后面的json串,-d前面的命令不变,下同):
{
"query": {
"match": {
"brand_name": "Apple Pay"
}
}
}
如果仅仅期望找到其中完全匹配的信息,则需要使用 match_phrase :
{
"query": {
"match_phrase": {
"brand_name": "Apple Pay"
}
}
}
这个命令只会返回brand_name严格等于”Apple Pay”的文档。
2、match 只要一个数组中的任意元素匹配上了,就会返回结果。比如
{"query":{"match":{"brand_name":"Apple"}}}
如果有一个文档是 “brand_name”:[“Apple”,”xiaomi”],那么这个文档也会被查询到。
DSL可以进行范围检索,-d 前面不变,后面的json串为:
{
"query": {
"bool": {
"filter": {
"range": {
"product_name": { "gt": "iphone5s" } }
},
"must": {
"match": {
"brand_name": "Apple" }
}
}
}
}
其中,bool下包含两个条件:
返回结果为iphone6s这个产品。
这属于bool query,是一种复合查询,逻辑的最外层由”bool”包裹。支持以下三种逻辑关系:
比如想要查询product_name=”P10”或”iphone6s”的文档,则可以用:
{
"query": {
"bool": {
"should": {
"match": {
"product_name": "iphone6s" }
},
"should": {
"match": {
"product_name": "P10" }
}
}
}
}
在下面的例子里,我们指定了要返回结果的数量、偏移位置(对分页有用)、要返回的字段和高亮显示的项。
{
"query": {
"match" : {
"brand_name": "Apple"
}
},
"size": 2,
"from": 0,
"_source": [ "title", "summary", "publish_date" ],
"highlight": {
"fields" : {
"title" : {}
}
}
}
ES可以使用PUT或者POST对文档进行更新(全部更新),如果指定ID的文档不存在,则执行插入操作,如果已经存在,则执行更新操作。
ES执行更新操作的时候,ES首先将旧的文档标记为删除状态,然后添加新的文档,旧的文档不会立即消失,但是你也无法访问,ES会在你继续添加更多数据的时候在后台清理已经标记为删除状态的文档。
比如上面插入id=1的文档的语句,再次执行一遍,不过把产品名改为了P9,则ES会先查看一下是否已经有id=1的文档了,如果有,则将原来的文档删除,然后增加一条新的id=1的文档。
curl -XPUT 11.11.11.11:30000/test_index/product/1 -d '{"brand_name" : "华为","product_name" : "P9"}'
返回结果为
{
"_index": "test_index",
"_type": "product",
"_id": "1",
"_version": 5,
"result": "updated",
"_shards": {
"total": 2,
"successful": 2,
"failed": 0
},
"created": false
}
可以看到,结果中说的是更新成功,而不是新建。
另外,只要指定了id,则不管是插入还是更新,PUT和POST都是等效的(这里的更新说的是全部更新,如果只是更新文档的某个字段,则只能用POST)。
但是如果不指定id,则只能是插入操作,且只能用POST,且此时ES会自动生成一个id。
不指定id的例子:
curl -XPOST 11.11.11.11:30000/test_index/product/ -d '{"brand_name" : "华为","product_name" : "P7"}'
结果新插入了一个文档,经查询,id为AWSwWYRTMurNist7umVh。
此时如果把-XPOST改为-XPUT,则会报错:
No handler found for uri [/test_index/product/] and method [PUT]
PUT操作是幂等的,即连续多次执行同一个PUT命令,与只执行一次命令,对数据库的影响是相同的。POST则不一定。通过这条原则也很好理解为什么不带id的时候不能用PUT了,因为每次执行都会新插入一条,违背了幂等原则。
curl -XPOST 11.11.11.11:30000/test_index/product/1/_update -d '{"doc":{"product_name":"P20"}}'
其中,POST不能改为PUT,_update表示更新操作,-d 中的 doc 表示对文档进行更新。
使用script也可以直接对某个id进行更新,实现同样的效果:
curl -XPOST 11.11.11.11:30000/test_index/product/1/_update?pretty -d '{"script":"ctx._source.product_name = \"P20\""}'
可以使用脚本(script)来实现对ES的复杂操作,包括update_by_query。
curl -XPOST 11.11.11.11:30000/test_index/product/_update_by_query?pretty -d '{"script":{"inline":"ctx._source.product_name=\"P30\""},"query":{"match":{"product_name":"P20"}}}'
以上命令实现了将product_name=P20的文档更新为product_name=P30。
curl -XDELETE 11.11.11.11:30000/test_index/product/1
上述命令删除了id=1的文档。