elasticsearch 第五篇(文档操作接口)
INDEX API
示例:
| 1 2 3 4 5 | PUT /test/user/1 { "name": "silence", "age": 27 } |
說明:
1.索引文檔使用PUT方法,需要指定index(test)、type(user)和文檔編號,提交數據為json格式為文檔的內容
2.在索引文檔時,會自動檢查index和type是否存在,若不存在則自動創建,對于type會自動調用putmapping方法為type自動創建mapping,當提交的json數據新增字段時也會自動對type自動調用putmapping方法在mapping中添加新的字段類型
可通過elasticsearch.yml中添加配置禁用自動創建index和type
| 1 2 | action.auto_create_index: false index.mapper.dynamic: false |
在某些時候允許某類型或者禁用某類型的index自動創建,則可以使用匹配模式和黑白名單形式進行配置
| 1 | action.auto_create_index: +test*,+temp*,+tmp* #只允許自動創建以test,temp,tmp開頭的index |
說明: 若action.auto_create_index設置為true或允許某些index執行, index.mapper.dynamic設置為false, 則可第一次時index自動創建一個type,后續不能再單獨創建新的type
3.文檔中的version屬性
es為每個文檔自動設置一個version屬性, version從1開始, 當文檔發生更新,刪除操作時version都會自增1, version是范圍為[1, 9.2e+18]的整數, 在獲取或查詢文檔是version作為文檔的一部分返回
version屬性主要使用樂觀鎖機保證數據在讀取后再進行更新動作時的數據一致性問題,在提交請求時通過指定version參數表示存儲的版本必須符合條件時才可執行成功, 默認條件為兩者一致,若不提交version表示不進行檢查
使用方法:
例如編號為1的文檔version為7
| 1 2 3 4 5 6 7 8 9 10 11 | { "_index": "test", "_type": "user", "_id": "1", "_version": 7, "found": true, "_source": { "name": "silence", "age": 27 } } |
當我們使用如下請求執行更新動作可看到執行成功,并且version自增1, 返回結果中為8:
輸入:
| 1 2 3 4 5 | PUT /test/user/1?version=7 { "name": "silence", "age": 28 } |
輸出:
| 1 2 3 4 5 6 7 | { "_index": "test", "_type": "user", "_id": "1", "_version": 8, "created": false } |
當我們再次發出version=7的請求得到的響應為:
| 1 2 3 4 | { "error": "VersionConflictEngineException[[test][2] [user][1]: version conflict, current [8], provided [7]]", "status": 409 } |
可自己測試version>8的請求依然失敗, 此時你可能會想到在高并發情況下此種效率是否會低效, 可能你會在內存中放置一個version+1的副本, 通過內存中對副本進行自增, 然后異步方式提高并發, 此時執行成功率會下降并且導致數據丟失, 在此種情況下只要滿足你指定的version大于存儲中的版本號即可, 為解決此種問題es提供version_type可以指定使用的比較策略:
| internal | 默認值, 表示指定version必須與存儲中的version一致, 若成功則存儲version自增1 |
| external/external_gt | 指定值必須大于存儲中的version, 若成功存儲version設置為提交的version |
| external_gte | 指定值必須大于等于存儲中的version, 若成功存儲version設置為提交的version |
| force | 強制更新,并將存儲version設置為提交的version |
4.op_type: 在提交請求時指定op_type=create, 表示若id不存在時創建, 否則失敗
輸入
| 1 2 3 4 5 | PUT /test/user/1?op_type=create { "name": "silence", "age": 28 } |
輸出:
| 1 2 3 4 | { "error": "DocumentAlreadyExistsException[[test][2] [user][1]: document already exists]", "status": 409 } |
op_type=create的另一種表示方法為:
| 1 2 3 4 5 | PUT user/1/_create { "name": "silence", "age": 28 } |
5.ID生成器: 在大多數情況下我們不需要維護也不關心文檔的id是什么, 在es中可以為文檔自動生成id,方式為使用post方式提交參數, 并在請求中不指定id值(若指定則使用指定的id值)
6.routing路由分配: 在創建index時通常會將index數據存放在不同的shard上,es默認通過hash(id) % shard_num決定將文檔存儲在哪個shard上,此刻你應該想到routing的作用,對,就是用來指定做負載是hash的輸入參數:
輸入:
| 1 2 3 4 5 | POST user/?routing=name { "name": "silence", "age": 28 } |
若在索引文檔時顯示指定routing,則在提交文檔中必須存在指定routing對應的值,否則執行失敗
7.分布式執行
索引操作會被路由到shard上,并在包含該shard的node中執行,若存在復制shard,則當所有復制節點從主shard中執行成功后,返回結果
8.一致性
為防止某些網絡節點錯誤,默認情況下當索引成功數量>=仲裁(replicas/2+1)時,則認為操作成功,對于復制數量為1時則數據一共存兩份(主shard和復制shard),此時若主shard寫成功則認為執行成功
可在elasticsearch.yml中將action.write_consistency設置為one,all,quorum修改判斷依據
9.刷新shard
為了在索引文檔成功后立即查詢到文檔(當shard刷新后才可search到), 可以通過設置refresh=true在索引文檔成功后立即執行存儲該數據shard的刷新動作, 在設置前應該對索引和查詢進行對性能測試,對于get接口獲取文檔是完全實時的
再次分享自己趟過的一個坑:
背景:需要在一堆日志中統計所有存在的源IP,日志時按天存放的,代碼結構如下:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | def get_all_store_hosts(): ''' 返回es中存儲中所有ip 在索引doc時未設置refresh ''' return _all_ def get_distinct_hosts_from_logs(day): ''' 從日志中查詢所有的ip并去重 ''' return _hosts_ def store_hosts(hosts) ''' 將新的ip存儲到es中 ''' def stat(day): _all_ = get_all_store_hosts() _hosts_ = get_distinct_hosts_from_logs: _hosts_ = [_host for _host in _hosts_ if _host not in _all_] if len(_hosts_): store_hosts(_hosts_) if __name__ == '__main__': for day in xrange(1, 30): stat(day) |
各位看著有問題嗎?好吧,貌似沒有問題,但是呢執行完成后,你會驚奇的發現es中你的統計的數據里面存儲大量重復的ip,問題原因大家已經知道了吧
解決方法:我在內存中做了一個緩存,通過緩存去重,當在緩存中不存在時則放入緩存中并存儲到es
當文檔被索引時會從主shard將數據復制到復制shard, 主shard需要等待復制shard的響應后返回執行結果, 此等待時間默認為1min, 可以通過在請求中添加timeout修改此時間
GET API
示例:
輸入:
GET /test/user/1
輸入:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | { "_index": "test", "_type": "user", "_id": "1", "_version": 3, "found": true, "_source": { "name": "silence", "age": 28, "book": { "name": "迷失的自己" } } } |
說明:
1.可以通過GET方法根據文檔的ID讀取文檔內容
_index,_type,_id三元組唯一標識一個文檔, 分別表示索引,類型和文檔id
_version為文檔的版本
found表示是否查詢到結果, true表示存在, false表示不存在
_source是真正的文檔內容
2.可以通過HEAD方法根據reponse header信息判斷文檔是否存在
輸入:curl -XHEAD -i "http://localhost:9200/test/user/1"
| 1 2 3 | HTTP/1.1 200 OK Content-Type: text/plain; charset=UTF-8 Content-Length: 0` |
輸入:curl -XHEAD -i "http://localhost:9200/test/user/1
輸出:
| 1 2 3 | HTTP/1.1 404 Not Found Content-Type: text/plain; charset=UTF-8 Content-Length: 0 |
可以看到若文檔存在使用HEAD方法則返回狀態碼為200,否則狀態碼為404
3.GET操作默認是實時的,也就是說文檔索引后可立即讀取,并不像Search需要等待shard刷新,但是通過在GET請求中通過參數realtime=false或者在elasticsearch.yml配置action.get.realtime:false禁用
4.在GET數據時可以使用”_all”替代要查詢的_type, 此時會返回在所有type中第一個匹配到的document
5.在GET數據時可以通過_source, _source_include & _source_exclude設置返回文檔包含的屬性
輸入:?GET /test/user/1?_source=false?不返回任何_source內容
輸入:?GET /test/user/1?_source=name?只返回_source中的name
輸入:?GET /test/user/1?_source_include=*.name&_source_exclude=name
_source常用于需要返回一兩個字段的情況, 內容較多的文檔屬性值進行篩選時可以組合_source_include和_source_exclude
6.若只想返回_source中的內容可以使用:GET /test/user/1/_source
7.若在索引文檔時指定了routing_key為了可以正確GET到文檔,則需要在GET請求中添加routing指定正確的routing_key
8.默認GET文檔執行在復制shard的上,但可以通過設置preference為_primary或者_local, _primary表示在主shard上執行, _local表示在一個分配且可用的shard上執行
9.GET請求中也可以添加refresh=true參數強制使獲取文檔相關shard刷新, 從而可以被search到
10.在GET請求發出后,會根據需要獲取文檔id將請求轉發到一個相關的復制節點上執行并返回結果
11.可以在GET請求中指定version屬性用于需要獲取符合規則version的文檔
DELETE API
示例:
輸入
DELETE /test/user/1
說明:
1.在DELETE方法提交的參數中可以設置version屬性用于刪除符合規則的version文檔
2.當在index文檔是設置routing_key, 那么在刪除文檔時也需要使用routing設置正確的routing_key
3.當刪除文檔是若index不存在, 則es會自動創建
4.刪除文檔請求會被轉發到主shard上, 主shard操作完成后, 各復制shard會從主shard進行同步
5.
from:?http://imsilence.github.io/2015/09/17/elasticsearch/elasticsearch_05/
總結
以上是生活随笔為你收集整理的elasticsearch 第五篇(文档操作接口)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: elasticsearch 第四篇(AP
- 下一篇: Elasticsearch之基本操作