索引员工文档:
PUT /megacorp/employee/1 { "first_name" : "John", "last_name" : "Smith", "age" : 25, "about" : "I love to go rock climbing", "interests": [ "sports", "music" ] }
检索文档:
GET /megacorp/employee/1
轻量搜索:
GET /megacorp/employee/_search
GET /megacorp/employee/_search?q=last_name:Smith
使用查询表达式:
GET /megacorp/employee/_search { "query" : { "match" : { "last_name" : "Smith" } } }
更复杂的搜索:
GET /megacorp/employee/_search { "query" : { "bool": { "must": { "match" : { "last_name" : "smith" } }, "filter": { "range" : { "age" : { "gt" : 30 } } } } } }
全文搜索:
GET /megacorp/employee/_search { "query" : { "match" : { "about" : "rock climbing" } } }
短语搜索:
GET /megacorp/employee/_search { "query" : { "match_phrase" : { "about" : "rock climbing" } } }
高亮搜索:
GET /megacorp/employee/_search { "query" : { "match_phrase" : { "about" : "rock climbing" } }, "highlight": { "fields" : { "about" : {} } } }
分析:
GET /megacorp/employee/_search { "aggs": { "all_interests": { "terms": { "field": "interests" } } } } GET /megacorp/employee/_search { "query": { "match": { "last_name": "smith" } }, "aggs": { "all_interests": { "terms": { "field": "interests" } } } } GET /megacorp/employee/_search { "aggs" : { "all_interests" : { "terms" : { "field" : "interests" }, "aggs" : { "avg_age" : { "avg" : { "field" : "age" } } } } } }
索引文档:
PUT /{index}/{type}/{id} { "field": "value", ... }
### 带id PUT /website/blog/123 { "title": "My first blog entry", "text": "Just trying this out...", "date": "2014/01/01" } ### 自动生成id POST /website/blog/ { "title": "My second blog entry", "text": "Still trying this out...", "date": "2014/01/01" }
取回一个文档:
GET /website/blog/123?pretty GET /website/blog/123?_source=title,text
检查文档是否存在:
### 用 HEAD 方法来代替 GET
### 文档存在返回200 OK,不存在返回 404 Not Found
curl -i -XHEAD http://localhost:9200/website/blog/123
更新整个文档:
### 如果想要更新现有的文档,需要 重建索引 或者进行替换, 我们可以使用相同的 index API 进行实现 PUT /website/blog/123 { "title": "My first blog entry", "text": "I am starting to get the hang of this...", "date": "2014/01/02" }
update API执行过程:
1. 从旧文档构建 JSON 2. 更改该 JSON 3. 删除旧文档 4. 索引一个新文档
创建新文档:
POST /website/blog/ { ... } PUT /website/blog/123?op_type=create { ... } PUT /website/blog/123/_create { ... }
删除文档:
DELETE /website/blog/123
乐观并发控制:
PUT /website/blog/1?version=1 { "title": "My first blog entry", "text": "Starting to get the hang of this..." } ### 外部版本控制 PUT /website/blog/2?version=5&version_type=external { "title": "My first external blog entry", "text": "Starting to get the hang of this..." }
文档的部分更新:
POST /website/blog/1/_update { "doc" : { "tags" : [ "testing" ], "views": 0 } } ### 使用脚本部分更新文档 POST /website/blog/1/_update { "script" : "ctx._source.views+=1" } POST /website/blog/1/_update { "script" : "ctx._source.tags+=new_tag", "params" : { "new_tag" : "search" } } ### 通过设置 ctx.op 为 delete 来删除基于其内容的文档 POST /website/blog/1/_update { "script" : "ctx.op = ctx._source.views == count ? 'delete' : 'none'", "params" : { "count": 1 } } ### 更新的文档可能尚不存在 ### 我们第一次运行这个请求时, upsert 值作为新文档被索引,初始化 views 字段为 1 。 在后续的运行中,由于文档已经存在, script 更新操作将替代 upsert 进行应用,对 views 计数器进行累加 POST /website/pageviews/1/_update { "script" : "ctx._source.views+=1", "upsert": { "views": 1 } } POST /website/pageviews/1/_update?retry_on_conflict=5 { "script" : "ctx._source.views+=1", "upsert": { "views": 0 } }
取回多个文档:
GET /_mget { "docs" : [ { "_index" : "website", "_type" : "blog", "_id" : 2 }, { "_index" : "website", "_type" : "pageviews", "_id" : 1, "_source": "views" } ] } ### 如果想检索的数据都在相同的 _index 中(甚至相同的 _type 中),则可以在 URL 中指定默认的 /_index 或者默认的 /_index/_type GET /website/blog/_mget { "docs" : [ { "_id" : 2 }, { "_type" : "pageviews", "_id" : 1 } ] } ### 如果所有文档的 _index 和 _type 都是相同的,你可以只传一个 ids 数组,而不是整个 docs 数组 GET /website/blog/_mget { "ids" : [ "2", "1" ] }
代价较小的批量操作:
格式: { action: { metadata }} { request body } { action: { metadata }} { request body } ... ### 每个子请求都是独立执行,因此某个子请求的失败不会对其他子请求的成功与否造成影响 POST /_bulk { "delete": { "_index": "website", "_type": "blog", "_id": "123" }} { "create": { "_index": "website", "_type": "blog", "_id": "123" }} { "title": "My first blog post" } { "index": { "_index": "website", "_type": "blog" }} { "title": "My second blog post" } { "update": { "_index": "website", "_type": "blog", "_id": "123", "_retry_on_conflict" : 3} } { "doc" : {"title" : "My updated blog post"} } ### 不要重复指定Index和Type ### 你仍然可以覆盖元数据行中的 _index 和 _type , 但是它将使用 URL 中的这些元数据值作为默认值 POST /website/log/_bulk { "index": {}} { "event": "User logged in" } { "index": { "_type": "blog" }} { "title": "Overriding the default type" }
空搜索:
### 返回集群中所有索引下的所有文档
GET /_search ### 应当注意的是 timeout 不是停止执行查询,它仅仅是告知正在协调的节点返回到目前为止收集的结果并且关闭连接。在后台,其他的分片可能仍在执行查询即使是结果已经被发送了 GET /_search?timeout=10ms
多索引、多类型
/_search 在所有的索引中搜索所有的类型 /gb/_search 在 gb 索引中搜索所有的类型 /gb,us/_search 在 gb 和 us 索引中搜索所有的文档 /g*,u*/_search 在任何以 g 或者 u 开头的索引中搜索所有的类型 /gb/user/_search 在 gb 索引中搜索 user 类型 /gb,us/user,tweet/_search 在 gb 和 us 索引中搜索 user 和 tweet 类型 /_all/user,tweet/_search 在所有的索引中搜索 user 和 tweet 类型
分页:
GET /_search?size=5 GET /_search?size=5&from=5 GET /_search?size=5&from=10
轻量搜索:
GET /_all/tweet/_search?q=tweet:elasticsearch ### 查询在 name 字段中包含 john 并且在 tweet 字段中包含 mary 的文档 ### 查询格式: +name:john +tweet:mary ### + 前缀表示必须与查询条件匹配。类似地, - 前缀表示一定不与查询条件匹配。没有 + 或者 - 的所有其他条件都是可选的——匹配的越多,文档就越相关 GET /_search?q=%2Bname%3Ajohn+%2Btweet%3Amary ### _all 字段 ### 当索引一个文档的时候,Elasticsearch 取出所有字段的值拼接成一个大的字符串,作为 _all 字段进行索引 GET /_search?q=mary ### name 字段中包含 mary 或者 john ### date 值大于 2014-09-10 ### _all 字段包含 aggregations 或者 geo ### 查询格式: +name:(mary john) +date:>2014-09-10 +(aggregations geo) GET /_search?q=%2Bname%3A(mary+john)+%2Bdate%3A%3E2014-09-10+%2B(aggregations+geo)
分析与分析器:
GET /_analyze { "analyzer": "standard", "text": "Text to analyze" }
映射:
### 查看映射 GET /gb/_mapping/tweet { "gb": { "mappings": { "tweet": { "properties": { "date": { "type": "date", "format": "strict_date_optional_time||epoch_millis" }, "name": { "type": "string" }, "tweet": { "type": "string" }, "user_id": { "type": "long" } } } } } } ### 删除映射 DELETE /gb ### 创建新映射 PUT /gb { "mappings": { "tweet" : { "properties" : { "tweet" : { "type" : "string", "analyzer": "english" }, "date" : { "type" : "date" }, "name" : { "type" : "string" }, "user_id" : { "type" : "long" } } } } } ### 在 tweet 映射增加一个新的名为 tag 的 not_analyzed 的文本域,使用 _mapping PUT /gb/_mapping/tweet { "properties" : { "tag" : { "type" : "string", "index": "not_analyzed" } } }
空查询:
GET /_search {} GET /index_2014*/type1,type2/_search {} GET /_search { "from": 30, "size": 10 }
查询表达式:
GET /_search { "query": YOUR_QUERY_HERE } GET /_search { "query": { "match_all": {} } } ### 查询语句结构 { QUERY_NAME: { ARGUMENT: VALUE, ARGUMENT: VALUE,... } } ### 如果是针对某个字段 { QUERY_NAME: { FIELD_NAME: { ARGUMENT: VALUE, ARGUMENT: VALUE,... } } } GET /_search { "query": { "match": { "tweet": "elasticsearch" } } } ### 合并查询语句 { "bool": { "must": { "match": { "email": "business opportunity" }}, "should": [ { "match": { "starred": true }}, { "bool": { "must": { "match": { "folder": "inbox" }}, "must_not": { "match": { "spam": true }} }} ], "minimum_should_match": 1 } }
最重要的查询:
### match_all 查询 { "match_all": {}} ### match 查询 ### 在执行查询前,它将用正确的分析器去分析查询字符串 { "match": { "tweet": "About Search" }} ### 如果在一个精确值的字段上使用它,例如数字、日期、布尔或者一个 not_analyzed 字符串字段,那么它将会精确匹配给定的值 { "match": { "age": 26 }} { "match": { "date": "2014-09-01" }} { "match": { "public": true }} { "match": { "tag": "full_text" }} ### multi_match 查询 { "multi_match": { "query": "full text search", "fields": [ "title", "body" ] } } ### range 查询 { "range": { "age": { "gte": 20, "lt": 30 } } } ### term 查询 { "term": { "age": 26 }} { "term": { "date": "2014-09-01" }} { "term": { "public": true }} { "term": { "tag": "full_text" }} ### terms 查询 { "terms": { "tag": [ "search", "full_text", "nosql" ] }} ### exists 查询和 missing 查询 { "exists": { "field": "title" } }
组合多查询:
{ "bool": { "must": { "match": { "title": "how to make millions" }}, "must_not": { "match": { "tag": "spam" }}, "should": [ { "match": { "tag": "starred" }} ], "filter": { "range": { "date": { "gte": "2014-01-01" }} ① } } } { "bool": { "must": { "match": { "title": "how to make millions" }}, "must_not": { "match": { "tag": "spam" }}, "should": [ { "match": { "tag": "starred" }} ], "filter": { "bool": { ① "must": [ { "range": { "date": { "gte": "2014-01-01" }}}, { "range": { "price": { "lte": 29.99 }}} ], "must_not": [ { "term": { "category": "ebooks" }} ] } } } } ### constant_score 查询 { "constant_score": { "filter": { "term": { "category": "ebooks" } } } }
验证查询:
### validate-query API 可以用来验证查询是否合法 GET /gb/tweet/_validate/query { "query": { "tweet" : { "match" : "really powerful" } } } ### 理解错误信息(下面的查询为一个非法查询) GET /gb/tweet/_validate/query?explain { "query": { "tweet" : { "match" : "really powerful" } } } ### 理解查询语句 GET /_validate/query?explain { "query": { "match" : { "tweet" : "really powerful" } } }
排序:
### 按照字段的值排序 GET /_search { "query" : { "bool" : { "filter" : { "term" : { "user_id" : 1 }} } }, "sort": { "date": { "order": "desc" }} } ### 多级排序 ### 假定我们想要结合使用 date 和 _score 进行查询,并且匹配的结果首先按照日期排序,然后按照相关性排序 GET /_search { "query" : { "bool" : { "must": { "match": { "tweet": "manage text search" }}, "filter" : { "term" : { "user_id" : 2 }} } }, "sort": [ { "date": { "order": "desc" }}, { "_score": { "order": "desc" }} ] } ## NOTE: Query-string 搜索 也支持自定义排序,可以在查询字符串中使用 sort 参数 GET /_search?sort=date:desc&sort=_score&q=search ### 多值字段的排序 ### 一种情形是字段有多个值的排序, 需要记住这些值并没有固有的顺序;一个多值的字段仅仅是多个值的包装,这时应该选择哪个进行排序呢? ### 对于数字或日期,你可以将多值字段减为单值,这可以通过使用 min 、 max 、 avg 或是 sum 排序模式 。 例如你可以按照每个 date 字段中的最早日期进行排序,通过以下方法 "sort": { "dates": { "order": "asc", "mode": "min" } }
字符串排序与多字段:
### 多字段映射 "tweet": { ① "type": "string", "analyzer": "english", "fields": { "raw": { ② "type": "string", "index": "not_analyzed" } } } ### 使用 tweet 字段用于搜索,tweet.raw 字段用于排序 GET /_search { "query": { "match": { "tweet": "elasticsearch" } }, "sort": "tweet.raw" }
搜索选项:
### 路由 GET /_search?routing=user_1,user2 ### 搜索类型 ### 缺省的搜索类型是 query_then_fetch 。 在某些情况下,你可能想明确设置 search_type 为 dfs_query_then_fetch 来改善相关性精确度 GET /_search?search_type=dfs_query_then_fetch
游标查询Scroll:
### 这个查询的返回结果包括一个字段 _scroll_id, 它是一个base64编码的长字符串 GET /old_index/_search?scroll=1m { "query": { "match_all": {}}, "sort" : ["_doc"], "size": 1000 } ### 然后我们能传递字段 _scroll_id 到 _search/scroll 查询接口获取下一批结果 GET /_search/scroll { "scroll": "1m", ① "scroll_id" : "cXVlcnlUaGVuRmV0Y2g7NTsxMDk5NDpkUmpiR2FjOFNhNnlCM1ZDMWpWYnRROzEwOTk1OmRSamJHYWM4U2E2eUIzVkMxalZidFE7MTA5OTM6ZFJqYkdhYzhTYTZ5QjNWQzFqVmJ0UTsxMTE5MDpBVUtwN2lxc1FLZV8yRGVjWlI2QUVBOzEwOTk2OmRSamJHYWM4U2E2eUIzVkMxalZidFE7MDs=" }
创建一个索引:
PUT /my_index { "settings": { ... any settings ... }, "mappings": { "type_one": { ... any mappings ... }, "type_two": { ... any mappings ... }, ... } }
如果你想禁止自动创建索引,你 可以通过在 config/elasticsearch.yml 的每个节点下添加下面的配置:
action.auto_create_index: false
删除索引:
### 删除单个 DELETE /my_index ### 删除多个 DELETE /index_one,index_two DELETE /index_* ### 删除全部 DELETE /_all DELETE /*
索引设置:
### 创建只有 一个主分片,没有副本的小索引 PUT /my_temp_index { "settings": { "number_of_shards" : 1, "number_of_replicas" : 0 } } ### 用 update-index-settings API 动态修改副本数 PUT /my_temp_index/_settings { "number_of_replicas": 1 }
配置分析器:
PUT /spanish_docs { "settings": { "analysis": { "analyzer": { "es_std": { "type": "standard", "stopwords": "_spanish_" } } } } } ### 测试分析器 GET /spanish_docs/_analyze?analyzer=es_std El veloz zorro marrón
自定义分析器:
### 自定义一个分析器 PUT /my_index { "settings": { "analysis": { "char_filter": { ... custom character filters ... }, "tokenizer": { ... custom tokenizers ... }, "filter": { ... custom token filters ... }, "analyzer": { ... custom analyzers ... } } } } PUT /my_index { "settings": { "analysis": { "char_filter": { "&_to_and": { "type": "mapping", "mappings": ["&=> and "] } }, "filter": { "my_stopwords": { "type": "stop", "stopwords": ["the", "a"] } }, "analyzer": { "my_analyzer": { "type": "custom", "char_filter": ["html_strip", "&_to_and"], "tokenizer": "standard", "filter": ["lowercase", "my_stopwords"] } } } } } ### 测试分析器 GET /my_index/_analyze?analyzer=my_analyzer The quick & brown fox ### 应用分析器 PUT /my_index/_mapping/my_type { "properties": { "title": { "type": "string", "analyzer": "my_analyzer" } } }
根对象:
### 禁用 _source 字段 PUT /my_index { "mappings": { "my_type": { "_source": { "enabled": false } } } } ### 在请求体中指定 _source 参数,来达到只获取特定的字段的效果 GET /_search { "query": { "match_all": {}}, "_source": [ "title", "created" ] } ### _all 字段 GET /_search { "match": { "_all": "john smith marketing" } } ### 禁用_all字段 PUT /my_index/_mapping/my_type { "my_type": { "_all": { "enabled": false } } } ### 设置_all字段 PUT /my_index/my_type/_mapping { "my_type": { "include_in_all": false, "properties": { "title": { "type": "string", "include_in_all": true }, ... } } }
动态映射:
### 参数 dynamic 可以用在根 object 或任何 object 类型的字段上 PUT /my_index { "mappings": { "my_type": { "dynamic": "strict", "properties": { "title": { "type": "string"}, "stash": { "type": "object", "dynamic": true } } } } }
自定义动态映射:
### 日期检测 ### 当 Elasticsearch 遇到一个新的字符串字段时,它会检测这个字段是否包含一个可识别的日期,比如 2014-01-01 。如果它像日期,这个字段就会被作为 date 类型添加。否则,它会被作为 string 类型添加 ### 日期检测可以通过在根对象上设置 date_detection 为 false 来关闭 PUT /my_index { "mappings": { "my_type": { "date_detection": false } } } ### 动态模板 ### es :以 _es 结尾的字段名需要使用 spanish 分词器。 ### en :所有其他字段使用 english 分词器。 ### match_mapping_type 允许你应用模板到特定类型的字段上,就像有标准动态映射规则检测的一样 PUT / my_index { "mappings": { "my_type": { "dynamic_templates": [{ "es": { "match": "*_es", ① "match_mapping_type": "string", "mapping": { "type": "string", "analyzer": "spanish" } } }, { "en": { "match": "*", ② "match_mapping_type": "string", "mapping": { "type": "string", "analyzer": "english" } } } ] } } } ### match 参数只匹配字段名称, path_match 参数匹配字段在对象上的完整路径,所以 address.*.name 将匹配这样的字段: { "address": { "city": { "name": "New York" } } }
缺省映射:
### 禁用缺省映射 PUT /my_index { "mappings": { "_default_": { "_all": { "enabled": false } }, "blog": { "_all": { "enabled": true } } } }
重新索引你的数据:
用 scroll 从旧的索引检索批量文档 , 然后用 bulk API 把文档推送到新的索引中。
从Elasticsearch v2.3.0开始, Reindex API 被引入。它能够对文档重建索引而不需要任何插件或外部工具。
GET /old_index/_search?scroll=1m { "query": { "range": { "date": { "gte": "2014-01-01", "lt": "2014-02-01" } } }, "sort": ["_doc"], "size": 1000 }
索引别名和零停机
### 设置别名 my_index 指向 my_index_v1 PUT /my_index_v1/_alias/my_index ### 检测别名指向哪一个索引 GET /*/_alias/my_index ### 或哪些别名指向这个索引 GET /my_index_v1/_alias/* ### 一个别名可以指向多个索引,所以我们在添加别名到新索引的同时必须从旧的索引中删除它。这个操作需要原子化,这意味着我们需要使用 _aliases 操作 POST /_aliases { "actions": [ { "remove": { "index": "my_index_v1", "alias": "my_index" }}, { "add": { "index": "my_index_v2", "alias": "my_index" }} ] }
近实时搜索:
### 默认情况下每个分片会每秒自动刷新一次。这就是为什么我们说 Elasticsearch 是 近 实时搜索: 文档的变化并不是立即对搜索可见,但会在一秒之内变为可见 ### 手动刷新 POST /_refresh POST /blogs/_refresh ### 设置刷新频率 PUT /my_logs { "settings": { "refresh_interval": "30s" } } ### 关闭自动刷新 PUT /my_logs/_settings { "refresh_interval": -1 } ### 每秒刷新 PUT /my_logs/_settings { "refresh_interval": "1s" }
持久化变更:
### 一次完整的提交会将段刷到磁盘 ### 片每30分钟被自动刷新(flush),或者在 translog 太大的时候也会刷新 ### 手动刷新 POST /blogs/_flush POST /_flush?wait_for_ongoing ### 慎重设置,确保你了解后果 ### 设置 durability 参数 PUT /my_index/_settings { "index.translog.durability": "async", "index.translog.sync_interval": "5s" }