ElasticSearchhtml
关于es的几个概念:node
集群:多个运行es节点能够组成一个集群,它们拥有相同的cluster.name。数据库
节点:运行es的实例json
索引:至关于数据库database,一个集群能够有多个索引(数据库)。 索引其实是指向一个或者多个物理分片的逻辑命名空间 数组
分片:索引的子集,一个索引能够被切成多个分片。分片又分为主分片和副分片,副分片是主分片的副本。一个分片是一个底层的工做单元 ,它仅保存了所有数据中的一部分。Elasticsearch 是利用分片将数据分发到集群内各处的。分片是数据的容器,文档保存在分片内,分片又被分配到集群内的各个节点里。 当你的集群规模扩大或者缩小时, Elasticsearch 会自动的在各节点中迁移分片,使得数据仍然均匀分布在集群里。并发
副本分片:一个副本分片只是一个主分片的拷贝。 副本分片做为硬件故障时保护数据不丢失的冗余备份,并为搜索和返回文档等读操做提供服务。副本分片数量能够随时更改。curl
类型:至关于数据库中的(表)table,一个索引(数据库)包含多个类型(表)。异步
文档:至关于表中的行(row)。jvm
字段:至关于表中的列(cloum)。elasticsearch
分配:将分片分配给某个节点。
在es中,每一个索引的主分片默认为5个,每一个主分片的副本默认为1个。
1、安装运行elasticsearch:
官网下载安装包:https://www.elastic.co/cn/downloads。其中5.5版本的须要jdk1.8的支持。
配置文件的更改,参考:http://www.cnblogs.com/ahaii/p/7279930.html
运行es:
elasticsearch/bin/elasticsearch -d
-d 参数表示以守候进程方式在后台运行。
查看是否运行成功:
curl http://localhost:9200/?pretty { "name" : "node-164", "cluster_name" : "elk-cluster", "cluster_uuid" : "QLhDVsXUR8yHrD8ts3JZBA", "version" : { "number" : "5.5.1", "build_hash" : "19c13d0", "build_date" : "2017-07-18T20:44:24.823Z", "build_snapshot" : false, "lucene_version" : "6.6.0" }, "tagline" : "You Know, for Search" }
?pretty参数使得结果以json方式显示。
2、利用es的RESTful API进行交互:
ElasticSearch提供RESTful API,经常使用格式为:
curl -X<VERB> '<PROTOCOL>://<HOST>:<PORT>/<PATH>?<QUERY_STRING>' -d '<BODY>'
其中:
-X<VBER>:能够指定curl发起是的请求方式,如GET、PUT、POST、DELETE、HEAD
<PATH>:API路径,如_cluster/stats、_nodes/stats/jvm
<QUERY_STRING>:查询字符串参数,如?pretty参数将以json格式显示查询结果
<BODY>:json格式的请求体
例如如下统计文档总数的请求格式:
curl -XGET 'http://localhost:9200/_count?pretty' -d ' { "query": { "match_all": {} } } '
一、建立文档:
curl -XPUT http://localhost:9200/索引(数据库)/类型(表)/id -d '{信息体}'
curl -XPUT http://localhost:9200/<index>/<type>/ID -d '{message}'
若是不指定id,es也支持随机生成一个id,可是,请求方法须要用POST:
curl -XPOST http://localhost:9200/<index>/<type>
自动生成的 ID 是 URL-safe、 基于 Base64 编码且长度为20个字符的 GUID 字符串。 这些 GUID 字符串由可修改的 FlakeID 模式生成,这种模式容许多个节点并行生成惟一 ID ,且互相之间的冲突几率几乎为零。
{ "_index": "people", "_type": "man", "_id": "AVFgSgVHUP18jI2wRx0w", "_version": 1, "created": true }
二、查询(检索)文档:
根据某ID检索:
curl -XGET http://localhost:9200/<index>/<type>/ID
该请求默认获取多有文档数据,且得到的数据放存在"_source"字段内。
只请求文档中一部分:
如,只须要id为5的文档中的name字段和job字段的值,则须要使用"?_source"字段:
curl -XGET http://localhost:9200/<index>/<type>/5?_source=name,job
所以,若是只须要文档中的数据,而不须要其余元数据(如索引,id,和类型),则可使用"_source":
curl -XGET http://localhost:9200/<index>/<type>/id/_source
检查一个文档是否存在:
curl -XHEAD http://loclhost:9200/<index>/<type>/id
这里使用的是HEAD请求方法,返回http状态码。若文档存在,则返回200。若不存在, 则返回404。
检索全部文档:
curl -XGET http://localhost:9200/<index>/<type>/_search
根据字符串检索:
curl -XGET http://localhost:9200/<index>/<type>/_search?q=name:ahaii
使用查询表达式检索:
curl -XGET http://localhost:9200/<index>/<type>/_search? -d ' { "query" : { "match" : { "name" : "ahaii" } } }'
使用过滤器检索:
curl -XGET http://localhost:9200/<index>/type/_search -d' { "query" : { "bool": { "must": { "match" : { "name" : "smith" } }, "filter": { "range" : { "age" : { "gt" : 20 } } } } } }'
注意,这里使用了filter过滤器,除了查询name是ahaii的外,还要匹配年龄大于20。
全文检索:
curl -XGET http://localhost:9200/<index>/<type>/_search -d ' { "query" : { "match" : { "about" : "like coding" } } }'
检索全部包含"like coding"字段的文档。
若是有多个文档包含该字段,则都会被返回。可是,es在返回结果中会添加一个“_score”字段。该字段是搜索结果的相关性得分。
相关性得分:
Elasticsearch 默认按照相关性得分对搜索结果进行排序,即每一个文档跟查询的匹配程度。彻底匹配查询条件的其相关性得分最高,也就排在搜索结果的第一个。其余包含查询条件某个字段的相关性得分就会较低,排在搜索结果的后面。
短语检索:
curl -XGET http://localhost:9200/<index>/<type>/_search { "query" : { "match_phrase" : { "about" : "like coding" } } }
这里使用的是"match_phrase",匹配结果里必须包含"like coding",且两个单词连在一块儿。
高亮检索:
curl -XGET http://locahost:9200/<index>/<type>/_search -d ' { "query" : { "match_phrase" : { "about" : "like coding" } }, "highlight": { "fields" : { "about" : {} } } }'
这里多了一个"highlight"部分,该部分包括了"about"属性匹配到的字段,而且以 HTML 标签 <em></em> 封装,以变化颜色。
三、更新文档:
在es中文档是不可改变的,即不能修改它们。当须要更新数据时,能够进行替换。
如如今id为5的文档数据以下:
curl -XGET http://localhost:9200/people/man/5 { "_index": "people", "_type": "man", "_id": "5", "_version": 1, "found": true, "_source": { "name": "ming", "age": 23, "job": "coding" } }
如今,须要更新"age"字段的值,操做及结果以下:
curl -XPUT http://localhost:9200/people/man/5 -d ' { "name":"ming", "age":29, "job":"coding" } ' #更新后结果以下: { "_index": "people", "_type": "man", "_id": "5", "_version": 2, "result": "updated", "_shards": { "total": 2, "successful": 2, "failed": 0 }, "created": false }
返回的结果中,"_version"字段由原来的1变成了2,"result"为"updated",且"created" 字段为"false"。
在内部,Elasticsearch 已将旧文档标记为已删除,并增长一个全新的文档。 尽管你不能再对旧版本的文档进行访问,但它并不会当即消失。当继续索引更多的数据,Elasticsearch 会在后台清理这些已删除文档。
从以上执行更新文档的操做中得出一个问题,在建立文档时,若是该文档已经存在,则会被覆盖。这结果可能不是咱们想要的,那怎么办?
前面介绍过,在建立文档时,可使用POST方法在建立文档时生成一个随机的ID,这样可确保文档不会重复(被覆盖)。可是若是我想本身指定ID呢?
因为es经过"_index"、"_type" 和"_id"三个字段来肯定一个惟一文档,所以咱们在建立文档时,必需要告诉es,只有这三个字段都不相同时才能建立新文档。这里有两种方法:
3.一、使用"?op_type=create"参数:
建立一个已经的文档:
curl -XPUT /people/man/5?op_type=create -d' { "name":"daka", "age":25, "job":"teacher" }' #返回结果: { "error": { "root_cause": [ { "type": "version_conflict_engine_exception", "reason": "[man][5]: version conflict, document already exists (current version [2])", "index_uuid": "_Xe9jJTdS6yKbGRBvet2qg", "shard": "1", "index": "people" } ], "type": "version_conflict_engine_exception", "reason": "[man][5]: version conflict, document already exists (current version [2])", "index_uuid": "_Xe9jJTdS6yKbGRBvet2qg", "shard": "1", "index": "people" }, "status": 409 }
因为"/people/man/5"文档已存在,再建立时,会提示409。
3.二、在url中使用"create"参数:
一样建立一个"/people/man/5"文档,一样返回409:
{ "error": { "root_cause": [ { "type": "version_conflict_engine_exception", "reason": "[man][5]: version conflict, document already exists (current version [2])", "index_uuid": "_Xe9jJTdS6yKbGRBvet2qg", "shard": "1", "index": "people" } ], "type": "version_conflict_engine_exception", "reason": "[man][5]: version conflict, document already exists (current version [2])", "index_uuid": "_Xe9jJTdS6yKbGRBvet2qg", "shard": "1", "index": "people" }, "status": 409 }
这样,就避免了旧文档被覆盖的状况。
四、删除文档:
curl -XDELETE http://localhost:9200/<index>/<type>/id
这里使用的是DELETE方法,成功删除后,返回如下结果:
{ "found": true, "_index": "people", "_type": "man", "_id": "5", "_version": 2, "result": "deleted", "_shards": { "total": 2, "successful": 2, "failed": 0 } }
注意,返回结果中的"_version"字段的值会增长,不管是否删除成功,该字段的值都会增长,这是 Elasticsearch 内部记录本的一部分,用来确保这些改变在跨多节点时以正确的顺序执行。
删除文档不会当即将文档从磁盘中删除,只是将文档标记为已删除状态。随着你不断的索引更多的数据,Elasticsearch 将会在后台清理标记为已删除的文档。
五、更新文档:
咱们知道,es中文档不能被直接修改,只能被替换。可使用update参数对文档进行更新的操做。 update API 简单使用与以前描述相同的 检索-修改-重建索引 的处理过程。
update 请求最简单的一种形式是接收文档的一部分做为 doc 的参数, 它只是与现有的文档进行合并。对象被合并到一块儿,覆盖现有的字段,增长新的字段。
curl -XPOST http://localhost:9200/people/man/5/_update { "doc": { "tel":"122334", "like":"football" } }
更新id为5的文档,添加"tel"和"like"两个字段。更新后的文档为:
{ "_index": "people", "_type": "man", "_id": "5", "_version": 4, "found": true, "_source": { "name": "ming", "age": 33, "job": "coding", "like": "football", "tel": "122334" } }
六、检索多个文档:
须要从 Elasticsearch 检索不少文档,那么使用 multi-get 或者 mget API 来将这些检索请求放在一个请求中,将比逐个文档请求更快地检索到所有文档。
mget API 要求有一个 docs 数组做为参数,每一个元素包含须要检索文档的元数据, 包括 _index 、 _type 和 _id 。若是你想检索一个或者多个特定的字段,那么你能够经过 _source 参数来指定这些字段的名字。一样,查询到的结果也包含在_source字段中:
curl -XGET http://localhost:9200/_mget -d ' { "docs" : [ { "_index" : "people", "_type" : "man", "_id" : 1 }, { "_index" : "people", "_type" : "man", "_id" : 2, "_source": "name" } ] }'
docs参数中包含两个查询条件,第一个查询符合这三个条件的整个文档的数据,第二个查询查询符合条件的文档的"name"字段的值。查询结果以下:
{ "docs": [ { "_index": "people", "_type": "man", "_id": "1", "_version": 1, "found": true, "_source": { "name": "ahaii", "age": 27, "job": "coding" } }, { "_index": "people", "_type": "man", "_id": "2", "_version": 1, "found": true, "_source": { "name": "fukk" } } ] }
若是要检索的文档在同一个index和type下,只须要传一个 ids 数组,而不是整个 docs 数组:
curl -XGET http://localhost:9200/people/man/_mget -d' { "ids":[3,5] }'
查询到的结果为:
{ "docs": [ { "_index": "people", "_type": "man", "_id": "3", "_version": 1, "found": true, "_source": { "name": "tim", "age": 32, "job": "stu" } }, { "_index": "people", "_type": "man", "_id": "5", "_version": 4, "found": true, "_source": { "name": "ming", "age": 33, "job": "coding", "like": "football", "tel": "122334" } } ] }
在检索多个文档时,若是其中某些文档不存在,则不会影响其余文档的检索。不存在的文档会返回false。
聚合检索:
该部分在之后详细介绍。
3、ElasticSearch中的避免冲突:
一、经过内部version参数避免冲突
Elasticsearch 是分布式的。当文档建立、更新或删除时, 新版本的文档必须复制到集群中的其余节点。Elasticsearch 也是异步和并发的,这意味着这些复制请求被并行发送,而且到达目的地时也许 顺序是乱的 。 Elasticsearch 须要一种方法确保文档的旧版本不会覆盖新的版本。
当咱们以前讨论 index , GET 和 delete 请求时,咱们指出每一个文档都有一个 _version (版本)号,当文档被修改时版本号递增。 Elasticsearch 使用这个 _version 号来确保变动以正确顺序获得执行。若是旧版本的文档在新版本以后到达,它能够被简单的忽略。
咱们能够利用 _version 号来确保 应用中相互冲突的变动不会致使数据丢失。咱们经过指定想要修改文档的 version 号来达到这个目的。 若是该版本不是当前版本号,咱们的请求将会失败。
按照_version的值对文档进行修改:
curl -XPUT http://localhost:9200/<index>/<type>/5?version=2 -d' { "name":"ming", "age":33, "job":"coding" }'
即,只有当前_version的值为2时,才会执行该操做。若是该不存在,则返回409。
ElasticSearch中,每次更新和删除,文档的_version字段都会加1。
二、经过version_type=external字段添加外部版本控制
外部版本号的处理方式和咱们以前讨论的内部版本号的处理方式有些不一样, Elasticsearch 不是检查当前 _version
和请求中指定的版本号是否相同, 而是检查当前 _version
是否 小于 指定的版本号。 若是请求成功,外部的版本号做为文档的新 _version
进行存储。
建立文档时设置外部版本号:
curl -XPUT http://localhost:9200/people/man/30?version=3&version_type=external -d '
{
"name":"tomi",
"age":42,
"job":"master"
}'
#返回结果: { "_index": "people", "_type": "man", "_id": "30", "_version": 3, "result": "created", "_shards": { "total": 2, "successful": 2, "failed": 0 }, "created": true }
能够看到,当前版本是3。如今更新这个文档,指定外部版本为5:
curl -XPUT http://localhost:9200/people/man/30?version=5&version_type=external -d ' { "name":"tomi", "age":19, "job":"master" } ' #返回结果: { "_index": "people", "_type": "man", "_id": "30", "_version": 5, "result": "updated", "_shards": { "total": 2, "successful": 2, "failed": 0 }, "created": false }
从返回结果看到,version被设置成了10。若再次请求,会返回409。