ElasticSearch深さページングソリューション

15267 ワード

  • 一般的な深さページング方式from+size
  • 別のページング方式scroll
  • scroll + scan

  • search_after方式
  • esライブラリscroll searchの実装


  • 一般的な深さページング方式from+size
    Esのデフォルトのページング方式はfrom+sizeの形式であり、深さページングの場合、この使用方式の効率は非常に低い.例えば、
    from=5000、size=10、esは各スライスに並べ替えて5000*10個の有効データを得、結果セットから最後の10個を取る必要がある.
    データはmongoのskip+sizeに似ています.
    効率的な問題に加えて、esが現在サポートしている最大skip値はmax_です.result_Windows、デフォルト
    10,000です.つまりfrom+size>max_result_Windowsの場合、esはエラーを返します
    [root@dnsserver ~]# curl -XGET 127.0.0.1:9200/custm/_settings?pretty 
    {
      "custm" : {
        "settings" : {
          "index" : {
            "max_result_window" : "50000",
             ....
           }
        }
      }
    }

    最初はオンラインのお客様のesデータに問題が発生し、数百ページに分割するとesはデータを返すことができません.このとき、正常な使用を回復するために、max_result_Windowsの値は50000に調整されます.
    [root@dnsserver ~]# curl -XPUT "127.0.0.1:9200/custm/_settings" -d 
    '{ 
        "index" : { 
            "max_result_window" : 50000 
        }
    }'

    そしてこの方法は一時的に問題を解決するしかなく、esの使用が多くなり、データ量が大きくなり、深さのページ分けのシーンが複雑になった場合、どのようにこの問題を解決しますか?
    別のページング方式scroll
    深さページングのシーンを満たすために、esはscroll方式でページング読み取りを提供する.原理的には、あるクエリに対してカーソルscroll_を生成します.id,後続のクエリは,結果セットで返されるhitsフィールドが空になるまで,このカーソルに基づいてデータを取得するだけで遍歴が終了することを示す.scroll_idの生成は,一時的な履歴スナップショットを確立したものと理解でき,その後の添削改ざんなどの操作はこのスナップショットの結果に影響を及ぼさない.
    curlを使用してページングの読み込み手順は、次のとおりです.
  • 最初のscroll_を取得id,urlパラメータは/index/_を含むtype/およびscroll、scrollフィールドはscroll_を指定します.idの有効生存期間は、分単位で、期限が切れた後にesによって自動的に整理されます.ドキュメントに特定のソートが必要ない場合は、ドキュメントが作成された時間に戻ると反復がより効率的になります.
  • [root@dnsserver ~]# curl -XGET 200.200.107.232:9200/product/info/_search?pretty&scroll=2m -d 
    '{"query":{"match_all":{}}, "sort": ["_doc"]}'
    
    #     
    {
      "_scroll_id": "cXVlcnlBbmRGZXRjaDsxOzg3OTA4NDpTQzRmWWkwQ1Q1bUlwMjc0WmdIX2ZnOzA7",
      "took": 1,
      "timed_out": false,
      "_shards": {
      "total": 1,
      "successful": 1,
      "failed": 0
      },
      "hits":{...}
    }
  • 以降のドキュメントは、前回のクエリで返されたscroll_を読み込みます.idは次のページを絶えず取りに来ます.もしsrc_idの生存期間が長いと、毎回戻るscroll_idはscroll_まで同じですidが期限切れになると、新しいscrollが返されます.id.指定したscroll_を要求idの場合は/index/_は必要ありませんtypeなどの情報が入っています.ページを読み込むたびにscroll_が再設定されます.idの生存時間は、現在のページを読み取るだけで十分であり、すべてのデータを読み取る時間を満たす必要はなく、1分で十分である.
  • [root@dnsserver ~]# curl -XGET '200.200.107.232:9200/_search/scroll?scroll=1m&scroll_id=cXVlcnlBbmRGZXRjaDsxOzg4NDg2OTpTQzRmWWkwQ1Q1bUlwMjc0WmdIX2ZnOzA7'
    
    #    
    {
        "_scroll_id": "cXVlcnlBbmRGZXRjaDsxOzk1ODg3NDpTQzRmWWkwQ1Q1bUlwMjc0WmdIX2ZnOzA7",
        "took": 106,
        "_shards": {
            "total": 1,
            "successful": 1,
            "failed": 0
        },
        "hits": {
            "total": 22424,
            "max_score": 1.0,
            "hits": [{
                    "_index": "product",
                    "_type": "info",
                    "_id": "did-519392_pdid-2010",
                    "_score": 1.0,
                    "_routing": "519392",
                    "_source": {
                        ....
                    }
                }
            ]
        }
    }
  • すべてのドキュメントを取得したら、scrollを手動でクリーンアップする必要があります.id .esには自動クリーンアップメカニズムがありますが、src_idの存在は、現在のクエリー結果セットイメージを保存するのに多くのリソースを費やし、ファイル記述子を占有します.だから使い終わったらすぐに片付けなければなりません.Esで提供されるCLEAR_の使用指定したscroll_を削除するAPIid
  • ##         srcoll_id 
    [root@dnsserver ~]# curl -XDELETE 127.0.0.1:9200/_search/scroll -d 
    '{"scroll_id" : ["cXVlcnlBbmRGZXRjaDsxOzg3OTA4NDpTQzRmWWkwQ1Q1bUlwMjc0WmdIX2ZnOzA7"]}'
    
    ##           scroll_id 
    [root@dnsserver ~]# curl -XDELETE 127.0.0.1:9200/_search/scroll/_all
    
    ##        scroll   
    [root@dnsserver ~]# curl -XGET 127.0.0.1:9200/_nodes/stats/indices/search?pretty
    {
      "cluster_name" : "200.200.107.232",
      "nodes" : {
        "SC4fYi0CT5mIp274ZgH_fg" : {
          "timestamp" : 1514346295736,
          "name" : "200.200.107.232",
          "transport_address" : "200.200.107.232:9300",
          "host" : "200.200.107.232",
          "ip" : [ "200.200.107.232:9300", "NONE" ],
          "indices" : {
            "search" : {
              "open_contexts" : 0,
              "query_total" : 975758,
              "query_time_in_millis" : 329850,
              "query_current" : 0,
              "fetch_total" : 217069,
              "fetch_time_in_millis" : 84699,
              "fetch_current" : 0,
              "scroll_total" : 5348,
              "scroll_time_in_millis" : 92712468,
              "scroll_current" : 0
            }
          }
        }
      }
    }
    

    scroll + scan
    scrollのドキュメントをソートする必要がない場合、esは検索の効率を高めるために、2.0バージョンでscroll+scanの方法を提供します.その後、2.1.0バージョンでscanの使用が削除され、この最適化がscrollに直接組み込まれました.moaラインのesバージョンは2.3なので、簡単に述べるだけです.使用するscanの方法はsearch_を指定することですtype=scan
    # 2.0-beta      scroll    ,       
    [root@dnsserver ~]# curl '127.0.0.1:9200/order/info/_search?scroll=1m&search_type=scan'  -d '{"query":{"match_all":{}}'

    search_アフタ方式
    上記のscroll searchの方法では、各scroll_idは、大量のリソース(特にソート要求)を占有するだけでなく、生成された履歴スナップショットであり、データの変更はスナップショットに反映されません.この方法は、データの移行やインデックスの変更など、大量のデータを非リアルタイムで処理する場合によく使用されます.では、リアルタイムで深さページングの問題を処理するとしたら?Esはsearch_を与えたafter方式では、>=5.0バージョンでのみ提供される機能です.
    search_afterのページング方法とscrollにはいくつかの顕著な違いがあります.まず、前のページの最後のデータに基づいて次のページの位置を決定します.また、ページング要求の過程で、インデックスデータの削除変更があれば、これらの変更もカーソルにリアルタイムで反映されます.
    各ページの最後のデータを見つけるには、各ドキュメントにグローバル一意の値が必要です.このページング方式は、現在のmoaメモリでrbtreeページングを使用する原理と同様に、公式に推奨されています.uidはグローバル一意の値として、実際にはビジネス層のidを使用してもよい.
  • 第1ページのリクエストは通常のリクエストと同様、
  • curl -XGET 127.0.0.1:9200/order/info/_search
    {
        "size": 10,
        "query": {
            "term" : {
                "did" : 519390
            }
        },
        "sort": [
            {"date": "asc"},
            {"_uid": "desc"}
        ]
    }
  • 第2ページの要求は、第1ページで結果の最後のデータの値を返し、search_を加える.afterフィールドで次のページを取り外します.注意、search_を使用afterの場合はfromを0または-1
  • に設定します.
    curl -XGET 127.0.0.1:9200/order/info/_search
    {
        "size": 10,
        "query": {
            "term" : {
                "did" : 519390
            }
        },
        "search_after": [1463538857, "tweet#654323"],
        "sort": [
            {"date": "asc"},
            {"_uid": "desc"}
        ]
    }

    まとめ:search_afterは、各ページのデータが前のページの最後のデータに依存するため、ページ要求をスキップできない深さページング+ソートに適しています.
    また、常に最新のデータが返され、ページング中にデータの位置が変更される可能性があります.このページング方式はmoaのビジネスシーンにもっと合っている.
    Esライブラリscroll searchの実装
    現在のサービス側のesバージョンは2.3に限られているため、より効率的なsearch_は使用できません.afterの方式は、一部のシーンではすべてのデータを取得するためにscrollの方式しか使用できません.以下はscroll_に基づくsearch実装のc API:
    es_cursor * co_es_scroll_search(char* esindex, char* estype, 
                        cJSON* query, cJSON* sort, cJSON* fields, int size, char* routing);
    BOOL        es_scroll_cursor_next(es_cursor* cursor);
    void        es_cursor_destroy(es_cursor* cursor);

    具体的な業務の使用シーンは以下の通りである.
    // 1.       scroll_id      
    es_cursor *cursor = co_es_scroll_search((char*)index_name,(char*)type_name,
                                            queryJ, sortJ, fieldJ, size , routing);
    // 2.          ,                  scroll_id       ,       
    while (es_scroll_cursor_next(cursor))
    {
        cJSON* data = es_cursor_json(cursor); //      
        ....  
    }
    // 3.     ,         scroll_id ,       
    es_cursor_destroy(cursor);

    添付:esバージョン変更記録は以下の通りです.
    2.0 -> 2.1 -> 2.2 -> 2.3 -> 2.4 -> 5.0 -> 5.1 -> 5.2 -> 5.3 -> 5.4 -> 5.5 -> 5.6 -> 6.0 -> 6.1