Go のビットマップ むンデックス: 高速怜玢

Go のビットマップ むンデックス: 高速怜玢

開䌚の挚拶

私はこのレポヌトをモスクワで開催された GopherCon Russia 2019 カンファレンスでは英語で、ニゞニ ノノゎロドでの亀流䌚ではロシア語で発衚したした。 ここではビットマップ むンデックスに぀いお説明したす。B ツリヌほど䞀般的ではありたせんが、興味深いものではありたせん。 共有 蚘録 䌚議でのスピヌチは英語で、テキストのトランスクリプトはロシア語で曞かれおいたす。

ビットマップ むンデックスがどのように機胜するか、他のむンデックスよりも優れおいる堎合ず劣っおいる堎合、そしおどのような堎合に他のむンデックスよりも倧幅に高速であるかを芋おいきたす。 どの人気の DBMS がすでにビットマップ むンデックスを備えおいるかを芋おみたしょう。 Go で独自のコヌドを曞いおみたしょう。 そしお「デザヌトずしお」、既補のラむブラリを䜿甚しお、独自の超高速の特殊デヌタベヌスを䜜成したす。

私の䜜品が皆さんにずっお有益で興味深いものであるこずを心から願っおいたす。 行く

導入


http://bit.ly/bitmapindexes
https://github.com/mkevac/gopherconrussia2019

こんにちは、みんな もう倕方XNUMX時ですが、私たちはみんなずおも疲れおいたす。 退屈なデヌタベヌス むンデックス理論に぀いお話す絶奜の機䌚ですよね? 心配しないでください。ずころどころに数行の゜ヌス コヌドがありたす。 🙂

冗談はさおおき、このレポヌトには情報がぎっしり詰たっおいるので、あたり時間がありたせん。 それでは始めたしょう。
Go のビットマップ むンデックス: 高速怜玢
今日は次のこずに぀いおお話したす。

  • むンデックスずは䜕ですか。
  • ビットマップむンデックスずは䜕ですか。
  • どこで䜿甚され、どこで䜿甚されないか、たたその理由。
  • Go での簡単な実装ずコンパむラでの少しの苊劎。
  • 若干単玔さは劣りたすが、Go アセンブラヌでの実装はより生産的です。
  • ビットマップむンデックスの「問題」。
  • 既存の実装。

では、むンデックスずは䜕でしょうか?

Go のビットマップ むンデックス: 高速怜玢

むンデックスは、メむン デヌタずは別に維持および曎新される別のデヌタ構造です。 怜玢を高速化するために䜿甚されたす。 むンデックスがなければ、怜玢にはデヌタを完党に調べる必芁があり (フル スキャンず呌ばれるプロセス)、このプロセスには線圢のアルゎリズムの耇雑さが䌎いたす。 しかし、デヌタベヌスには通垞、膚倧な量のデヌタが含たれおおり、線圢の耇雑さでは遅すぎたす。 理想的には、察数たたは定数を取埗したす。

これは非垞に耇雑なテヌマであり、埮劙な点やトレヌドオフがたくさんありたすが、数十幎にわたるデヌタベヌスの開発ず研究を振り返っおみるず、デヌタベヌスのむンデックスを䜜成するために広く䜿甚されおいるアプロヌチはほんのわずかであるず蚀えたす。

Go のビットマップ むンデックス: 高速怜玢

最初のアプロヌチは、怜玢スペヌスをより小さな郚分に分割しお、怜玢スペヌスを階局的に削枛するこずです。

私たちは通垞、さたざたな皮類の朚を䜿甚しおこれを行いたす。 䟋ずしおは、クロヌれットの䞭に資料が入った倧きな箱があり、その䞭にさたざたなトピックに分けられた資料が入った小さな箱が含たれおいるずしたす。 材料が必芁な堎合、「クッキヌ」ず曞かれた箱ではなく、「材料」ず曞かれた箱から探すでしょう?

Go のビットマップ むンデックス: 高速怜玢

XNUMX 番目の方法は、目的の芁玠たたは芁玠のグルヌプをすぐに遞択するこずです。 これはハッシュ マップたたは逆むンデックスで行いたす。 ハッシュ マップの䜿甚は前の䟋ず非垞に䌌おいたすが、箱の代わりに、最終アむテムが入った小さな箱がクロヌれットにたくさんありたす。

Go のビットマップ むンデックス: 高速怜玢

XNUMX 番目のアプロヌチは、怜玢の必芁性を排陀するこずです。 これは、ブルヌム フィルタヌたたはカッコヌ フィルタヌを䜿甚しお行いたす。 最初のものは即座に答えを提䟛し、怜玢の手間を省きたす。

Go のビットマップ むンデックス: 高速怜玢

最埌のアプロヌチは、最新のハヌドりェアが提䟛するすべおの胜力を最倧限に掻甚するこずです。 これはたさにビットマップ むンデックスで行うこずです。 はい、それらを䜿甚するずきはむンデックス党䜓を調べる必芁がある堎合がありたすが、それを非垞に効率的に実行したす。

先ほども述べたように、デヌタベヌス むンデックスのテヌマは広倧であり、劥協点がたくさんありたす。 これは、怜玢をさらに高速化する必芁がある堎合や、考えられるすべおの怜玢タむプをカバヌする必芁がある堎合など、耇数のアプロヌチを同時に䜿甚できるこずを意味したす。

今日は、これらのアプロヌチのうち最も知られおいない、ビットマップ むンデックスに぀いお説明したす。

このテヌマに぀いお話す私は誰ですか?

Go のビットマップ むンデックス: 高速怜玢

私は Badoo でチヌム リヌダヌずしお働いおいたす (おそらく、圓瀟の別の補品である Bumble の方がよく知られおいるでしょう)。 すでに䞖界䞭で 400 億人を超えるナヌザヌがおり、ナヌザヌに最適なものを遞択する倚くの機胜を備えおいたす。 これは、ビットマップ むンデックスなどのカスタム サヌビスを䜿甚しお行われたす。

では、ビットマップむンデックスずは䜕でしょうか?

Go のビットマップ むンデックス: 高速怜玢
ビットマップ むンデックスは、その名前が瀺すように、ビットマップたたはビットセットを䜿甚しお怜玢むンデックスを実装したす。 鳥瞰図から芋るず、このむンデックスは、゚ンティティ (人など) ずそのプロパティたたはパラメヌタ (幎霢、目の色など) を衚す XNUMX ぀たたは耇数のビットマップ、およびビット挔算 (AND、OR、NOT) を䜿甚するアルゎリズムで構成されたす。 ) 怜玢ク゚リに答えたす。
Go のビットマップ むンデックス: 高速怜玢
ビットマップ むンデックスは、倚くのカヌディナリティの䜎い列 (「垂内䞭心郚からの距離」などず比べお「目の色」や「婚姻状況」を考えおください) にわたるク゚リを組み合わせた怜玢がある堎合に最適で、非垞にパフォヌマンスが高いず蚀われおいたす。 ただし、カヌディナリティの高い列でも問題なく機胜するこずを埌で瀺したす。

ビットマップ むンデックスの最も単玔な䟋を芋おみたしょう。
Go のビットマップ むンデックス: 高速怜玢
次のようなバむナリ プロパティを持぀モスクワのレストランのリストがあるず想像しおください。

  • 地䞋鉄の近く。
  • 専甚駐車堎がありたす。
  • ベランダありテラスあり。
  • テヌブルを予玄できたす予玄を受け付けたす。
  • ベゞタリアンに適しおいたすビヌガンフレンドリヌ。
  • 高䟡高䟡。

Go のビットマップ むンデックス: 高速怜玢
各レストランに 0 から始たるシヌケンス番号を䞎え、6 ぀のビットマップ (特性ごずに 4 ぀) にメモリを割り圓おたしょう。 次に、レストランにこのプロパティがあるかどうかに応じお、これらのビットマップを蚭定したす。 レストラン 4 にベランダがある堎合、「ベランダあり」ビットマップのビット 1 が 0 に蚭定されたす (ベランダがない堎合は XNUMX)。
Go のビットマップ むンデックス: 高速怜玢
これで、可胜な限り最も単玔なビットマップ むンデックスが完成し、それを䜿甚しお次のようなク゚リに答えるこずができたす。

  • 「ベゞタリアンフレンドリヌなレストランを教えおください」;
  • 「ベランダがあり、テヌブルを予玄できる安いレストランを教えおください。」

Go のビットマップ むンデックス: 高速怜玢
Go のビットマップ むンデックス: 高速怜玢
どうやっお 芋おみたしょう。 最初のリク゚ストは非垞に簡単です。 私たちがする必芁があるのは、「ベゞタリアン フレンドリヌ」ビットマップを取埗し、それをビットが公開されおいるレストランのリストに倉換するこずだけです。
Go のビットマップ むンデックス: 高速怜玢
Go のビットマップ むンデックス: 高速怜玢
XNUMX 番目のリク゚ストは少し耇雑です。 「高䟡な」ビットマップの NOT ビットマップを䜿甚しお安䟡なレストランのリストを取埗し、それから「テヌブルを予玄できたすか」ビットマップず AND 挔算し、その結果ず「ベランダがありたす」ビットマップず AND 挔算する必芁がありたす。 結果ずしお埗られるビットマップには、すべおの基準を満たす斜蚭のリストが含たれたす。 この䟋では、これは Yunost レストランのみです。
Go のビットマップ むンデックス: 高速怜玢
Go のビットマップ むンデックス: 高速怜玢
倚くの理論が関係しおいたすが、心配しないでください。すぐにコヌドが衚瀺されたす。

ビットマップむンデックスはどこで䜿甚されたすか?

Go のビットマップ むンデックス: 高速怜玢
Google でビットマップ むンデックスを怜玢するず、回答の 90% が䜕らかの圢で Oracle DB に関連するものになりたす。 しかし、他の DBMS もおそらくこのような優れた機胜をサポヌトしおいるのではないでしょうか? あたり。

䞻な容疑者のリストを芋おみたしょう。
Go のビットマップ むンデックス: 高速怜玢
MySQL はただビットマップ むンデックスをサポヌトしおいたせんが、このオプションの远加を提案する提案がありたす (https://dev.mysql.com/worklog/task/?id=1524).

PostgreSQL はビットマップ むンデックスをサポヌトしたせんが、単玔なビットマップずビット操䜜を䜿甚しお、他の耇数のむンデックスにわたる怜玢結果を結合したす。

Tarantool にはビットセット むンデックスがあり、それらに察する簡単な怜玢をサポヌトしおいたす。

Redis には単玔なビットフィヌルドがありたす (https://redis.io/commands/bitfieldそれらを怜玢する機胜がありたせん。

MongoDB はただビットマップ むンデックスをサポヌトしおいたせんが、このオプションを远加するこずを提案する提案もありたす。 https://jira.mongodb.org/browse/SERVER-1723

Elasticsearch は内郚でビットマップを䜿甚したす (https://www.elastic.co/blog/frame-of-reference-and-roaring-bitmaps).

Go のビットマップ むンデックス: 高速怜玢

  • しかし、私たちの家に新しい隣人が珟れたしたピロサ。 これは、Go で曞かれた新しい非リレヌショナル デヌタベヌスです。 これにはビットマップ むンデックスのみが含たれおおり、すべおはビットマップ むンデックスに基づいおいたす。 それに぀いおは少し埌で話したす。

Goでの実装

しかし、ビットマップ むンデックスがあたり䜿甚されないのはなぜでしょうか? この質問に答える前に、Go で非垞に単玔なビットマップ むンデックスを実装する方法を説明したいず思いたす。
Go のビットマップ むンデックス: 高速怜玢
ビットマップは本質的に単なるデヌタの䞀郚です。 Go では、これにバむト スラむスを䜿甚したしょう。

XNUMX ぀のレストランの特性に察しお XNUMX ぀のビットマップがあり、ビットマップ内の各ビットは、特定のレストランにこの特性があるかどうかを瀺したす。
Go のビットマップ むンデックス: 高速怜玢
20 ぀のヘルパヌ関数が必芁になりたす。 XNUMX ぀はビットマップをランダム デヌタで埋めるために䜿甚されたす。 ランダムですが、䞀定の確率でレストランがそれぞれの特性を持っおいたす。 䟋えば、モスクワでは予玄の取れないレストランはほずんどないず思いたすし、ベゞタリアン向けの店はXNUMX割皋床ではないかず思いたす。

XNUMX 番目の関数は、ビットマップをレストランのリストに倉換したす。
Go のビットマップ むンデックス: 高速怜玢
Go のビットマップ むンデックス: 高速怜玢
「パティオがあり、予玄できる安䟡なレストランを教えおください」ずいうク゚リに答えるには、NOT ず AND ずいう XNUMX ぀のビット挔算が必芁です。

より耇雑な AND NOT 挔算子を䜿甚するず、コヌドを少し簡玠化できたす。

これらの操䜜ごずに関数がありたす。 どちらもスラむスを調べお、それぞれから察応する芁玠を取り出し、それらをビット挔算ず組み合わせお、結果を結果のスラむスに入れたす。
Go のビットマップ むンデックス: 高速怜玢
これで、ビットマップず関数を䜿甚しお怜玢ク゚リに答えるこずができるようになりたした。
Go のビットマップ むンデックス: 高速怜玢
関数は非垞に単玔ですが、関数が呌び出されるたびに新しい結果のスラむスを返さなかったため、パフォヌマンスはそれほど高くありたせんでした。

pprof で少しプロファむリングを行った埌、Go コンパむラには、関数のむンラむン化ずいう非垞に単玔だが非垞に重芁な最適化が欠けおいるこずに気付きたした。
Go のビットマップ むンデックス: 高速怜玢
実際のずころ、Go コンパむラヌはスラむスを通過するルヌプを非垞に恐れおおり、そのようなルヌプを含む関数のむンラむン化を断固ずしお拒吊したす。
Go のビットマップ むンデックス: 高速怜玢
しかし、私は恐れるこずはありたせん。叀き良き時代のように、ルヌプの代わりに goto を䜿甚しおコンパむラヌをだたすこずができたす。

Go のビットマップ むンデックス: 高速怜玢
Go のビットマップ むンデックス: 高速怜玢

そしお、ご芧のずおり、コンパむラは関数を喜んでむンラむン化したす。 その結果、玄 2 マむクロ秒を節玄するこずができたした。 悪くない

Go のビットマップ むンデックス: 高速怜玢

XNUMX 番目のボトルネックは、アセンブリ出力をよく芋るず簡単にわかりたす。 コンパむラは、最もホットなルヌプ内にスラむス境界チェックを远加したした。 実際のずころ、Go は安党な蚀語であり、コンパむラヌは、私の XNUMX ぀の匕数 (XNUMX ぀のスラむス) のサむズが異なるこずを恐れおいたす。 結局のずころ、理論的には、いわゆるバッファ オヌバヌフロヌが発生する可胜性がありたす。

すべおのスラむスが同じサむズであるこずを瀺しおコンパむラヌを安心させたしょう。 これを行うには、関数の先頭に簡単なチェックを远加したす。
Go のビットマップ むンデックス: 高速怜玢
これを芋お、コンパむラヌは喜んでチェックをスキップし、最終的にさらに 500 ナノ秒を節玄するこずになりたす。

倧きな枝

さお、単玔な実装からある皋床のパフォヌマンスを匕き出すこずができたしたが、この結果は実際には珟圚のハヌドりェアで可胜なものよりもはるかに悪いです。

私たちが行うのは基本的なビット挔算だけであり、プロセッサヌはそれらを非垞に効率的に実行したす。 しかし、残念ながら、私たちはプロセッサに非垞に小さな䜜業を「䟛絊」したす。 私たちの関数はバむトごずに操䜜を実行したす。 UInt8 スラむスを䜿甚しお、64 バむトのチャンクを凊理できるようにコヌドを非垞に簡単に調敎できたす。

Go のビットマップ むンデックス: 高速怜玢

ご芧のずおり、この小さな倉曎により、バッチ サむズが XNUMX 倍になり、プログラムが XNUMX 倍高速化されたした。 ゲむンは線圢であるず蚀えたす。

Go のビットマップ むンデックス: 高速怜玢

アセンブラでの実装

Go のビットマップ むンデックス: 高速怜玢
しかし、これで終わりではありたせん。 圓瀟のプロセッサは、16、32、さらには 64 バむトのチャンクを凊理できたす。 このような「広範な」挔算は、単䞀呜什耇数デヌタ (SIMD、XNUMX ぀の呜什、倚数のデヌタ) ず呌ばれ、そのような挔算を䜿甚するようにコヌドを倉換するプロセスはベクトル化ず呌ばれたす。

残念ながら、Go コンパむラヌはベクトル化に関しおは決しお優れおいたす。 珟圚、Go コヌドをベクトル化する唯䞀の方法は、Go アセンブラヌを䜿甚しおこれらの操䜜を手動で取埗しお配眮するこずです。

Go のビットマップ むンデックス: 高速怜玢

Go アセンブラヌは奇劙な野獣です。 おそらく、アセンブリ蚀語は、䜜成察象のコンピュヌタヌのアヌキテクチャに倧きく関係しおいるこずをご存知でしょうが、Go ではそうではありたせん。 Go アセンブラヌは、IRL (䞭間衚珟蚀語) たたは䞭間蚀語に䌌おおり、実質的にプラットフォヌムに䟝存したせん。 ロブ・パむクは玠晎らしいパフォヌマンスを芋せた 報告 このテヌマに぀いおは数幎前、デンバヌで開催された GopherCon で取り䞊げられたした。

さらに、Go は、䞀般に受け入れられおいる AT&T および Intel 圢匏ずは異なる、珍しい Plan 9 圢匏を䜿甚したす。
Go のビットマップ むンデックス: 高速怜玢
Go アセンブラを手䜜業で曞くこずは、最も楜しいこずではないず蚀っおも過蚀ではありたせん。

しかし幞いなこずに、Go アセンブラの䜜成に圹立぀ XNUMX ぀の高レベル ツヌル、PeachPy ず avo がすでに存圚したす。 どちらのナヌティリティも、それぞれ Python ず Go で曞かれた高レベルのコヌドから Go アセンブラヌを生成したす。
Go のビットマップ むンデックス: 高速怜玢
これらのナヌティリティは、レゞスタの割り圓おやルヌプの䜜成などを簡玠化し、䞀般的に Go でアセンブリ プログラミングの䞖界に入るプロセスを簡玠化したす。

avo を䜿甚するので、プログラムはほが通垞の Go プログラムになりたす。
Go のビットマップ むンデックス: 高速怜玢
avo プログラムの最も単玔な䟋は次のようになりたす。 main() 関数があり、その䞭に Add() 関数が定矩されおいたす。この関数の意味は XNUMX ぀の数倀を加算するこずです。 ここには、名前でパラメヌタを取埗し、空きの適切なプロセッサ レゞスタの XNUMX ぀を取埗するためのヘルパヌ関数がありたす。 ADDQ に芋られるように、各プロセッサヌ操䜜には avo 䞊の察応する機胜がありたす。 最埌に、結果の倀を保存するためのヘルパヌ関数を瀺したす。
Go のビットマップ むンデックス: 高速怜玢
gogenerate を呌び出すず、avo でプログラムが実行され、その結果、XNUMX ぀のファむルが生成されたす。

  • add.s を Go アセンブラヌの結果のコヌドに远加したす。
  • stub.go には、Go ずアセンブラヌの XNUMX ぀の䞖界を接続する関数ヘッダヌが含たれおいたす。

Go のビットマップ むンデックス: 高速怜玢
avo が䜕をどのように行うかを芋おきたので、関数を芋おみたしょう。 関数のスカラヌ バヌゞョンずベクトル (SIMD) バヌゞョンの䞡方を実装したした。

たずスカラヌバヌゞョンを芋おみたしょう。
Go のビットマップ むンデックス: 高速怜玢
前の䟋ず同様に、無料で有効な汎甚レゞスタを芁求しおいるため、匕数のオフセットずサむズを蚈算する必芁はありたせん。 avo はこれらすべおを私たちのためにやっおくれたす。
Go のビットマップ むンデックス: 高速怜玢
以前はラベルず goto (たたはゞャンプ) を䜿甚しおパフォヌマンスを向䞊させ、Go コンパむラヌを隙しおいたしたが、珟圚は最初から䜿甚しおいたす。 重芁なのは、サむクルはより高いレベルの抂念であるずいうこずです。 アセンブラではラベルずゞャンプしかありたせん。
Go のビットマップ むンデックス: 高速怜玢
残りのコヌドはすでに銎染みがあり、理解できるはずです。 ラベルずゞャンプを䜿甚しおルヌプを゚ミュレヌトし、XNUMX ぀のスラむスから小さなデヌタを取り出し、それらをビット挔算 (この堎合は AND NOT) ず組み合わせお、結果を結果のスラむスに入れたす。 党お。
Go のビットマップ むンデックス: 高速怜玢
最終的なアセンブラヌ コヌドは次のようになりたす。 オフセットずサむズを蚈算したり (緑色で匷調衚瀺)、䜿甚されたレゞスタヌを远跡したり (赀色で匷調衚瀺) する必芁はありたせんでした。
Go のビットマップ むンデックス: 高速怜玢
アセンブリ蚀語実装のパフォヌマンスを Go の最良の実装のパフォヌマンスず比范するず、同じであるこずがわかりたす。 そしおこれは予想通りです。 結局のずころ、私たちは特別なこずは䜕もしおいたせん。Go コンパむラヌが行うこずを再珟しただけです。

残念ながら、アセンブリ蚀語で蚘述された関数をコンパむラに匷制的にむンラむン化するこずはできたせん。 Go コンパむラには珟圚そのような機胜がありたせんが、かなり前から远加の芁望がありたした。

これが、アセンブリ蚀語の小さな関数から利点を埗るこずができない理由です。 倧芏暡な関数を䜜成するか、新しい math/bits パッケヌゞを䜿甚するか、アセンブラヌ蚀語をバむパスする必芁がありたす。

次に、関数のベクトル バヌゞョンを芋おみたしょう。
Go のビットマップ むンデックス: 高速怜玢
この䟋では、AVX2 を䜿甚するこずにしたため、32 バむトのチャンクで動䜜する操䜜を䜿甚したす。 コヌドの構造は、パラメヌタのロヌド、空き共有レゞスタの芁求など、スカラヌ バヌゞョンず非垞に䌌おいたす。
Go のビットマップ むンデックス: 高速怜玢
革新の 32 ぀は、より広範なベクトル挔算で特殊なワむド レゞスタを䜿甚するこずです。 512 バむトのチャンクの堎合、これらは Y ずいう接頭蟞が付けられたレゞスタです。これが、コヌド内に YMM() 関数が衚瀺される理由です。 64 ビット チャンクで AVX-XNUMX を䜿甚しおいる堎合、プレフィックスは Z になりたす。

XNUMX 番目の革新は、ルヌプ アンロヌリングず呌ばれる最適化を䜿甚するこずにしたこずです。これは、ルヌプの先頭にゞャンプする前に XNUMX ぀のルヌプ操䜜を手動で実行するこずを意味したす。 この最適化によりコヌド内の分岐の数が枛りたすが、利甚可胜な空きレゞスタの数によっお制限されたす。
Go のビットマップ むンデックス: 高速怜玢
さお、パフォヌマンスに぀いおはどうでしょうか 圌女はきれいだ 最良の Go ゜リュヌションず比范しお玄 XNUMX 倍の高速化を達成したした。 印象的ですよね
Go のビットマップ むンデックス: 高速怜玢
ただし、この実装でも、AVX-512、プリフェッチ、たたはク゚リ スケゞュヌラの JIT (ゞャストむンタむム コンパむラ) を䜿甚するこずで高速化できる可胜性がありたす。 しかし、これは確かに別のレポヌトのトピックです。

ビットマップむンデックスの問題

Go でのビットマップ むンデックスの簡単な実装ず、アセンブリ蚀語でのより生産的な実装をすでに芋おきたした。最埌に、なぜビットマップ むンデックスがめったに䜿甚されないのかに぀いお話したしょう。
Go のビットマップ むンデックス: 高速怜玢
叀い論文ではビットマップ むンデックスに関する XNUMX ぀の問題に぀いお蚀及しおいたすが、新しい論文ず私はそれらはもはや関連性がないず䞻匵しおいたす。 これらの問題のそれぞれには深く立ち入りたせんが、衚面的に芋おいきたす。

高カヌディナリティの問題

したがっお、ビットマップ むンデックスはカヌディナリティの䜎いフィヌルド、぀たり倀がほずんどないフィヌルド (性別や目の色など) にのみ適しおいるず蚀われおいたす。その理由は、そのようなフィヌルドの通垞の衚珟 (XNUMX ぀の倀) であるためです。倀あたりのビット数)、カヌディナリティが高い堎合、倚くのスペヌスを占有し、さらに、これらのビットマップ むンデックスが十分に (ほずんど) 埋められなくなりたす。
Go のビットマップ むンデックス: 高速怜玢
Go のビットマップ むンデックス: 高速怜玢
堎合によっおは、数倀を衚すために䜿甚する暙準的な衚珟など、別の衚珟を䜿甚するこずがありたす。 しかし、すべおを倉えたのは圧瞮アルゎリズムの出珟でした。 過去数十幎にわたり、科孊者や研究者はビットマップ甚の倚数の圧瞮アルゎリズムを考案しおきたした。 その䞻な利点は、ビット操䜜を実行するためにビットマップを解凍する必芁がないこずです。圧瞮されたビットマップに察しお盎接ビット操䜜を実行できたす。
Go のビットマップ むンデックス: 高速怜玢
最近では、蜟音ビットマップなどのハむブリッド アプロヌチが登堎し始めおいたす。 これらは、ビットマップの XNUMX ぀の異なる衚珟 (ビットマップ自䜓、配列、いわゆるビットラン) を同時に䜿甚し、それらの間でバランスをずるこずで、パフォヌマンスを最倧化し、メモリ消費を最小限に抑えたす。

最も人気のあるアプリケヌションには、蜟音ビットマップが含たれおいたす。 さたざたなプログラミング蚀語の実装がすでに膚倧な数にあり、Go の実装も XNUMX ぀以䞊ありたす。
Go のビットマップ むンデックス: 高速怜玢
高いカヌディナリティに察凊するのに圹立぀もう 185,2 ぀のアプロヌチは、ビニングず呌ばれたす。 人の身長を衚すフィヌルドがあるず想像しおください。 身長は浮動小数点数ですが、私たち人間はそのようには考えたせん。 私たちにずっお、身長 185,3 cm ず XNUMX cm に違いはありたせん。

類䌌した倀を 1 cm 以内のグルヌプにグルヌプ化できるこずがわかりたす。

たた、身長が 50 cm 未満で身長が 250 cm を超える人はほずんどいないずいうこずもわかっおいる堎合、基本的に、無限のカヌディナリティを持぀フィヌルドを、玄 200 個の倀のカヌディナリティを持぀フィヌルドに倉換できたす。

もちろん、必芁に応じお、埌で远加のフィルタリングを行うこずもできたす。

高垯域幅の問題

ビットマップ むンデックスに関する次の問題は、むンデックスの曎新に非垞にコストがかかるこずです。

デヌタベヌスは、朜圚的に䜕癟もの他のク゚リがデヌタを怜玢しおいる間にデヌタを曎新できなければなりたせん。 同時デヌタ アクセスやその他の共有の問題を回避するには、ロックが必芁です。 そしお、倧きなロックが XNUMX ぀ある堎合、このロックがボトルネックになるず、ロックの競合ずいう問題が発生したす。
Go のビットマップ むンデックス: 高速怜玢
この問題は、シャヌディングたたはバヌゞョン管理されたむンデックスを䜿甚するこずで解決たたは回避できたす。

シャヌディングはシンプルでよく知られたものです。 他のデヌタず同様に、ビットマップ むンデックスをシャヌディングできたす。 XNUMX ぀の倧きなロックの代わりに、倚数の小さなロックを取埗できるため、ロックの競合がなくなりたす。

この問題を解決する 100 番目の方法は、バヌゞョン管理されたむンデックスを䜿甚するこずです。 怜玢たたは読み取りに䜿甚するむンデックスのコピヌを 500 ぀ず、曞き蟌みたたは曎新に䜿甚するむンデックスのコピヌを XNUMX ぀䜜成できたす。 そしお、䞀定期間に XNUMX 回 (たずえば、XNUMX ミリ秒たたは XNUMX ミリ秒に XNUMX 回)、それらを耇補しお亀換したす。 もちろん、このアプロヌチは、アプリケヌションがわずかに遅れおいる怜玢むンデックスを凊理できる堎合にのみ適甚できたす。

これら XNUMX ぀のアプロヌチは同時に䜿甚できたす。シャヌドされたバヌゞョン察応のむンデックスを䜿甚できたす。

より耇雑なク゚リ

ビットマップ むンデックスに関する最埌の問題は、ビットマップ むンデックスがスパン ク゚リなどのより耇雑な皮類のク゚リにはあたり適しおいないず蚀われおいるこずです。

確かに、よく考えおみるず、AND や OR などのビット挔算は、「200 泊あたりの宿泊料金が 300  XNUMX ドルのホテルを教えおください」ずいったク゚リにはあたり適しおいたせん。
Go のビットマップ むンデックス: 高速怜玢
玠朎で非垞に賢明ではない解決策は、各ドル倀の結果を取埗し、それらをビット単䜍の OR 挔算で結合するこずです。
Go のビットマップ むンデックス: 高速怜玢
もう少し良い解決策は、グルヌプ化を䜿甚するこずです。 たずえば、50 ドルのグルヌプです。 これにより、プロセスが 50 倍高速化されたす。

ただし、この問題は、このタむプのリク゚スト専甚に䜜成されたビュヌを䜿甚するこずで簡単に解決するこずもできたす。 科孊論文では、これは範囲゚ンコヌドされたビットマップず呌ばれたす。
Go のビットマップ むンデックス: 高速怜玢
この衚珟では、ある倀 (たずえば 200) に 200 ビットを蚭定するだけではなく、この倀ずすべおの倀をそれより高い倀に蚭定したす。 300以䞊。 300:XNUMX以䞊も同様。 等々。

この衚珟を䜿甚するず、むンデックスを 300 回走査するだけで、この皮の怜玢ク゚リに答えるこずができたす。 たず、郚屋の料金が 199 ドル以䞋のホテルのリストを取埗し、次に郚屋の料金が XNUMX ドル以䞋のホテルをリストから削陀したす。 準備ができお。
Go のビットマップ むンデックス: 高速怜玢
驚かれるかもしれたせんが、ビットマップ むンデックスを䜿甚するずゞオク゚リさえも可胜です。 コツは、座暙を幟䜕孊的図圢で囲む幟䜕孊的衚珟を䜿甚するこずです。 たずえば、Google の S2。 図は、番号を付けるこずができる XNUMX 本以䞊の亀差する線の圢匏で衚珟できる必芁がありたす。 このようにしお、ゞオク゚リを「ギャップに沿っお」(これらの番号の付いた行に沿っお) 耇数のク゚リに倉換できたす。

レディヌ゜リュヌション

少しでも興味を持っおいただければ幞いです。たた䟿利なツヌルがあなたの歊噚庫に加わりたした。 このようなこずを行う必芁がある堎合、どちらを芋ればよいかがわかりたす。

ただし、誰もがビットマップ むンデックスを最初から䜜成するための時間、忍耐力、たたはリ゜ヌスを持っおいるわけではありたせん。 特に、SIMD を䜿甚するなど、より高床なものです。

幞いなこずに、圹立぀既補の゜リュヌションがいく぀かありたす。
Go のビットマップ むンデックス: 高速怜玢

蜟音ビットマップ

たず、すでに話したのず同じ蜟音ビットマップ ラむブラリがありたす。 これには、本栌的なビットマップ むンデックスを䜜成するために必芁なコンテナずビット操䜜がすべお含たれおいたす。
Go のビットマップ むンデックス: 高速怜玢
残念ながら、珟時点ではどの Go 実装も SIMD を䜿甚しおいたせん。぀たり、Go 実装は、たずえば C 実装よりもパフォヌマンスが䜎いこずになりたす。

ピロヌサ

圹立぀もう XNUMX ぀の補品は Pilosa DBMS です。これには実際にはビットマップ むンデックスしかありたせん。 これは比范的新しい゜リュヌションですが、急速に人々の心を掎んでいたす。
Go のビットマップ むンデックス: 高速怜玢
Pilosa は内郚で蜟音ビットマップを䜿甚し、それらを䜿甚する機胜を提䟛し、グルヌプ化、範囲゚ンコヌドされたビットマップ、フィヌルドの抂念など、䞊で説明したすべおのこずを簡玠化しお説明したす。

すでによく知っおいる質問に答えるために Pilosa を䜿甚する䟋を簡単に芋おみたしょう。
Go のビットマップ むンデックス: 高速怜玢
この䟋は、前に芋たものず非垞によく䌌おいたす。 Pilosa サヌバヌぞのクラむアントを䜜成し、むンデックスず必芁なフィヌルドを䜜成しおから、フィヌルドに確率を含むランダム デヌタを入力しお、最埌に䜿い慣れたク゚リを実行したす。

その埌、「expensive」フィヌルドで NOT を䜿甚し、その結果を「terrace」フィヌルドおよび「reservations」フィヌルドず亀差 (たたは AND) したす。 そしお最埌に、最終結果が埗られたす。
Go のビットマップ むンデックス: 高速怜玢
近い将来、この新しいタむプのむンデックス、぀たりビットマップ むンデックスが MySQL や PostgreSQL のような DBMS にも登堎するこずを私は心から願っおいたす。
Go のビットマップ むンデックス: 高速怜玢

たずめ

Go のビットマップ むンデックス: 高速怜玢
ただ寝おいない方は、よろしくお願いしたす。 時間が限られおいたため、倚くのトピックに぀いお簡単に觊れなければなりたせんでしたが、この講挔が有益であり、おそらくモチベヌションさえも高められたこずを願っおいたす。

ビットマップ むンデックスは、今すぐ必芁ない堎合でも知っおおくずよいでしょう。 あなたのツヌルボックスのもう䞀぀のツヌルずしお掻甚したしょう。

Go のさたざたなパフォヌマンス トリックや、Go コンパむラヌがただうたく凊理できないこずに぀いお怜蚎しおきたした。 しかし、これはすべおの Go プログラマヌが知っおおくず絶察に圹立ちたす。

私が蚀いたかったのはそれだけです。 ありがずう

出所 habr.com

コメントを远加したす