天天看點

5、Elasticsearch 索引文檔的CRUD

我們知道文檔 document 是 ES 的最小資料單元,ES 也提供了豐富的操作索引文檔的 API,這裡使用 Kibana 搜尋,檢視和與存儲在 ES 索引中的資料進行互動,關于如何安裝和配置 Kibana ,打算後面再專門梳理。

1、建立測試索引

下面說明 ES 索引文檔的 CRUD 操作。開始之前,先建立一個測試索引,并對索引 index 進行一些必要的性能優化設定,同時定義和設定文檔字段的屬性:

PUT mytest_index_0626
{
    "settings": {
        "index": {
            "number_of_shards": "9", //分片數
            "number_of_replicas": "0", //副本數
            "refresh_interval": "3s", //重新整理頻率
            "translog": { //設定事務日志,防止資料丢失
                "durability": "async",
                "flush_threshold_size": "1024mb",
                "sync_interval": "120s"
            },
            "merge": {
                "scheduler": {
                    "max_thread_count": "2" //歸并線程的數目
                }
            },
            "mapping": {
                "total_fields": {
                    "limit": 20000 //限制單個文檔字段的總數
                }
            }
        }
    },
    "mappings": {
        "properties": {
            "pkey": {
                "type": "keyword"
            },
            "flag": {
                "type": "long"
            },
            "myObj": {
                "type": "object"
            },
            "status": {
                "type": "keyword"
            }
        }
    }
}
           

在設定 settings.index.xxxx 考慮了 ES 的性能調優,感興趣可以參考:

  • translog:Elasticsearch 之 Translog - 簡書
  • merge:es的索引合并_ITduan621的部落格-CSDN部落格_es合并索引
  • mapping.total_fields.limit:es“limit of total fields” 和“field expansion mathes too many fields”問題解決_jff_shihaoren的部落格-CSDN部落格

在 Kibana 執行建立索引指令,效果如下:

5、Elasticsearch 索引文檔的CRUD

2、添加文檔

>> POST 索引名/_doc

5、Elasticsearch 索引文檔的CRUD

請注意,如果沒有指定文檔id,ES 會自動生成文檔id。也可以指定文檔id,如下:

POST mytest_index_0626/_doc/1
{
  "pkey": "15556905954_10011",
  "flag": "1",
  "myObj": {
    "user_id":"15556905954",
    "create_time":"20220626110020",
    "sign_no":"10011",
    "remarks":"testing creat a document."
  },
  "status": "N"
}
           

如果添加文檔時,使用了已存在的文檔id,則會把之前的文檔更新覆寫掉:(_version 用于記錄目前最新的版本,_seq_no=2說明該文檔已經被更新過2次了!)

5、Elasticsearch 索引文檔的CRUD

3、删除文檔

方式一:使用 DELETE 方式删除

5、Elasticsearch 索引文檔的CRUD

文檔id為1的已被标記删除,ES内部也重新整理了被删除文檔的_version和_seq_no,查詢語句是不會查詢到這條文檔資料了!

方式二:使用 POST 方式 + _delete_by_query

5、Elasticsearch 索引文檔的CRUD

先根據查詢 API 比對到對應的文檔,然後調用 _delete_by_query 進行删除,這種方式是最常用的,隻需要比對到要删除的目标文檔,就可以删除或批量删除。

請注意,如果要删除的文檔資料量很大,Kibana 可能會傳回并提示"504 GetWay Time-out":

5、Elasticsearch 索引文檔的CRUD

 不要慌,我們可以通過下面的 API 進行追蹤:

GET _tasks?detailed=true&actions=*/delete/byquery
// 或者這個也可以查詢
GET _tasks?detailed=true&actions=*byquery
           

它會把叢集中所有節點在進行删除動作的任務給羅列出來,我們找到剛剛删除的任務即可,如下:

5、Elasticsearch 索引文檔的CRUD

 如果我想中途取消删除任務的執行,找到這個删除任務ID,使用以下指令即可:

POST _tasks/r1A2WoRbTwKZ516z6NEs5A:36619/_cancel
           

4、更新文檔

方式一:使用 _update

假如我們要更新文檔的部分字段,如果直接使用 PUT 索引名/文檔id 更新,則會導緻文檔的全量更新,這是極其危險和不可取的操作!可以使用如下方式進行文檔的增量更新:

POST mytest_index_0626/_doc/1/_update
{
  "doc":{
    "status" :"A"
  }
}
           

通過查找官網文檔中的 _update API,目前看流行的寫法是采用 script 腳本方式,比如,在某個文檔裡新增一個字段:

5、Elasticsearch 索引文檔的CRUD

又比如,在某個文檔裡删除一個字段:

5、Elasticsearch 索引文檔的CRUD

 當然,還有使用 painless 語言的 script 用法,這裡不再嘗試了,有需要可以參考官網文檔的API示例和說明。

方式二:使用 _update_by_query

其實,平時最常用的更新文檔方式則是"按查詢更新",它支援批量更新操作,而官網文檔也有對 _update_by_query 的用法說明。

現在為目前索引再添加2條文檔,該索引一共有3條資料了。下面開始示範不同更新需求的示例

>> 更新所有文檔的 flag 字段為0

POST mytest_index_0626/_update_by_query?conflicts=proceed
{
    "script": {
       "source": "ctx._source['flag']=0",
        "lang": "painless"
    },
    "query": {
        "match_all": {}
    }
}

// 傳回:
{
  "took" : 46,
  "timed_out" : false,
  "total" : 3,
  "updated" : 3,
  "deleted" : 0,
  "batches" : 1,
  "version_conflicts" : 0,
  "noops" : 0,
  "retries" : {
    "bulk" : 0,
    "search" : 0
  },
  "throttled_millis" : 0,
  "requests_per_second" : -1.0,
  "throttled_until_millis" : 0,
  "failures" : [ ]
}
           

查詢結果顯示:

5、Elasticsearch 索引文檔的CRUD

 >> 更新所有文檔的 flag 字段為1,且 status 字段為 U

POST mytest_index_0626/_update_by_query?conflicts=proceed
{
    "script": {
       "source": """
          ctx._source['flag']=1;
          ctx._source['status']='U';
       """,
       "lang": "painless"
    },
    "query": {
        "match_all": {}
    }
}
           

查詢結果顯示:

5、Elasticsearch 索引文檔的CRUD

  >> 更新所有文檔的 flag 字段為0,且更新myObj裡的remarks為空字元串,且為myObj裡新增一個update_time字段并指派為目前時間

POST mytest_index_0626/_update_by_query?conflicts=proceed
{
    "script": {
       "source": """
          ctx._source['flag']=0;
          ctx._source['myObj'].remarks='';
          ctx._source['myObj'].update_time='20220626113059';
       """,
       "lang": "painless"
    },
    "query": {
        "match_all": {}
    }
}
           

查詢結果顯示:

5、Elasticsearch 索引文檔的CRUD

最後,總結下 _update_by_query:

  • 如果文檔存在該字段,則會使用新值覆寫舊值,不存在該字段的話,則會添加該字段為目前索引的類型字段;
  • 如果被更新的文檔資料量較大時,也會出現 "504 GetWay Time-out" 問題,可以使用以下指令跟蹤更新進度:GET _tasks?detailed=true&actions=*byquery
  • 請求指令的字尾參數 conflicts=proceed 的含義是,當更新遇到沖突時跳過,一般可以在傳回結果的"version_conflicts"看到發生版本沖突的數量;
  • 有時候,"version_conflicts"可能不為0,也就是說更新操作過程中遇到了版本沖突,這是由于目前索引的文檔版本号被其他正在運作的指令或程式改變了,與執行 _update_by_query 指令時讀取的索引快照不一緻。我遇到這種情況時,會在整體更新完畢後,再執行一次該指令,保證版本比對,進而能更新文檔并增加版本号;
  • _update_by_query 是按查詢批量更新的,是以改變查詢條件會得到不一樣的更新結果,還有要注意_update_by_query 不支援分頁操作("from": 0,"size": 1000),如果需要用到分頁更新操作,可以在字尾參數使用 scroll_size=1000;

5、查詢文檔

我們知道 ES 是一個強大的搜尋和分析引擎,自然在文檔檢索上會提供豐富多樣的 API。比如,根據文檔id查詢:

// 根據文檔id查詢
GET mytest_index_0626/_doc/ZBEwmoEBTXtCd1dvEzpC?pretty
// 根據文檔id批量查詢
GET mytest_index_0626/_doc/_mget?pretty
{
  "ids":["ZBEwmoEBTXtCd1dvEzpC","axEwmoEBTXtCd1dvuDqv","gxHImYEBTXtCd1dv3Dfj"]
}
           

比如,查詢所有,或按文檔的字段進行查詢(GET 或 POST 方式都可以):

# 查詢所有
GET mytest_index_0626/_search?pretty&track_total_hits=true
POST mytest_index_0626/_search?pretty&track_total_hits=true
# 按字段查詢
GET mytest_index_0626/_search?pretty&q=pkey:15556905959_10011
POST mytest_index_0626/_search?pretty&q=status:U
           

以上這些都隻是最最最最基礎的查詢,如果從 ES 文檔檢索的整體角度來看,大緻可以分為兩種查詢類型:結構化檢索和全文檢索。那麼,結構化檢索和全文檢索各有什麼特點呢?

結構化檢索:

  • 針對的字段類型有:數字,日期,時間,及精确的文本等;
  • 結構化檢索不去關心檔案的相關度或評分,而是會對文檔進行包含或排除的處理,也就是說要麼存在要麼不存在!

全文檢索:

  • 針對的字段類型有:全文本字段,比如:email位址,産品名稱等;
  • 全文檢索會使用每個字段的分析器進行字元串查詢。

為了看清楚更詳細的分類,我畫了一張腦圖:

5、Elasticsearch 索引文檔的CRUD

 限于篇幅,這些查詢方式将在下篇進行詳細介紹和使用示範。

繼續閱讀