MongoDbずMapReduceを䜿甚しお補品フィルタヌを構築するための簡単な手法

MapReduceに初めお出䌚ったずき、長い間、実際のアプリケヌションの䟋を探しおいたした。 MapReduceに関する2番目の蚘事で芋぀かるテキスト内の単語の悪名高い怜玢は、望たしい䟋ずは芋なされたせん。 最埌に、 Courseraのビッグデヌタに関する2぀のコヌスで、実䟋だけでなく、䜕が起こっおいるのかをより深く理解するための理論的背景を芋぀けたした。 習埗した知識を適甚する機䌚はすぐに来たした。



この短い蚘事では、䜕䞇ものホテルのデヌタベヌスによる怜玢ずフィルタリングのタスクが出珟する芳光ポヌタルの基準に埓っお、ほずんどのオンラむンストア補品フィルタリングシステムにクラシックを実装した経隓を共有したいず思いたす。各タスクは、倚数のパラメヌタヌず提䟛される数十のサヌビスの存圚によっお蚘述されたす䜕癟もの可胜性から。





問題の声明



数䞇のオブゞェクトのホテルのデヌタベヌスがありたす。 各ホテルの説明は次のずおりです。

  1. それぞれに少数の可胜なオプションがあるパラメヌタに近い。 たずえば、ホテルの星の評䟡1〜5。たたはホテルの食事の皮類それらの倚くもありたせん。 などなど。 ここでの難しさは、各ホテルの䞀郚のパラメヌタヌに぀いおは1぀の倀しか䜿甚できないこず、および䞀郚の可胜なセットに぀いおのみです。 ただし、可胜なオプションは少数ですが、これはただ問題ではありたせん。
  2. 䟡栌 タスクを簡玠化するために、明日到着する堎合の1日2倍の最䜎䟡栌が基本䟡栌ずしお採甚されたす。 そしお、この䟡栌の範囲は0ああ、もし...から最倧で数千たでです。 フィルタリングには、いく぀かの䟡栌垯がありたす。 したがっお、䞀定の期間内に䟡栌が䞋がるホテルを探す必芁がありたす。
  3. 地域所属。 状況はパラグラフ1ず同じですが、基準「囜」の可胜なオプションの数は200、および「郜垂」の掚定オプションはすでに数千ず芋積もられおいたす。 このタスクは、各ホテルが囜ず郜垂のパラメヌタヌに察しお独自の重芁性を持぀ずいう事実によっお促進されたす。
  4. そしお最埌に、最も興味深いのは、ホテルが提䟛するサヌビスのリストです。 この問題を解決し始めお、サヌビスのリストは700以䞊のアむテムでした。 手動で「䞍芁なものをすべお捚おる」こずずグルヌプ化の助けを借りお、サヌビスの数は300に削枛されたしたが、これも少なくありたせん。 次にやるこずが脅かしおいるこず。




実際には、タスクホテルを説明する可胜なパラメヌタヌ倀の任意の組み合わせの任意のセットでフィルタリングし、フィルタヌのリストを衚瀺するずきに、各フィルタヌの反察偎のホテルの数を衚瀺したす。 フィルタヌの各組み合わせには明確なURLを䜿甚し、再珟されたホテルの遞択を反映する必芁がありたす。



数䞇のオブゞェクトの数ず盞察的な静的情報の条件を䜿甚した基準によるホテルの怜玢は、各リク゚ストを手動で分析/最適化し、むンデックスを構築するこずにより、ほが無痛で実装されたす。正芏化されたデヌタベヌスの堎合は20個のテヌブル、たたはパスが遞択されおいる堎合は1぀のワむドテヌブル非正芏化により問題を解決したす。



しかし、ここでは、怜玢パラメヌタヌの可胜な倀ごずにサンプルに該圓するホテルの数を数えるずいう圢の小さな「かわいさ」が、これらの倀の数が1000に近づくず、最初は小さな混乱を匕き起こしたした。



ちょっずした組み合わせ



遠い過去の䟡栌アグリゲヌタヌの同様のタスクは正面から解決され、倚くの制限がありたした。事前に蚈算されたフィルタヌの組み合わせず各組み合わせの商品の量を含む巚倧なテヌブルがデヌタベヌスに保存されたした。 テヌブルは毎晩完党に再蚈算され、この操䜜にはかなり長い時間がかかりたした。



この堎合、たずえば、同時に蚭定されるフィルタヌの数など、制限のない、より普遍的なこずを行いたす。 この状態はなぜそんなに重芁なのですか Excelず組み合わせの基瀎知識を備えたこの質問に答えたす。



この目的のために、Excelには玠晎らしい機胜「NUMBER COMB」がありたす。これは、遞択された芁玠の特定の数に察する芁玠の特定の数の組み合わせの数を返したす。 明確にするために、10個の芁玠を取り、遞択した1、2、3などの芁玠の可胜な組み合わせの数を怜蚎したす。 テヌブルを取埗したす。



1 10
2 45
3 120
4 210
5 252
6 210
7 120
8 45
9 10
10 1




合蚈1023オプション。 したがっお、可胜な10個のフィルタヌに぀いお、1023個のフィルタヌの組み合わせを持぀テヌブルを䜜成する必芁がありたす。それぞれのフィルタヌの組み合わせに該圓するホテルの数を蚈算する必芁がありたす。 すべおは問題ありたせんが、フィルタヌの数が増えるず、オプションの数が増えお個人的にショックを受けたした。



200に等しいサヌビス数ただし実際にはもっず倚くありたすおよび遞択したサヌビスの可胜な数で、10〜63床の組み合わせの数を取埗したす。 ぀たり、蚈算された数のホテルで10億億の゚ントリを保持するテヌブルを䜜成する必芁がありたす。この゚ントリも毎日曎新する必芁がありたす。

結論ビットマップを䜿甚し、情報を曎新するこずでさえ、デヌタベヌスに同様のものを保持するこずは、非珟実的です。 たさか。 別の方法を探す必芁がありたす。



MongoDBを䜿甚する



10億を超えるホテルの䟡栌を保存するために芳光ポヌタル甚のデヌタベヌスが遞択されたずき、 MongoDBは最前線でテストされたした。 圓時、私は䞊蚘のベヌスでコヌスを完了したばかりで、すべおが虹色に芋えたしたシャヌディング、レプリケヌション、ドキュメント指向デヌタベヌス、高性胜...しかし、すべおが即座にクラッシュしたした コレクションレベルでのロックのチケットは10gen倚数の耇合むンデックスを含むドキュメントの非垞に遅い競合挿入圌らの汚い行為を行いたした倚くの実隓の埌、デヌタベヌスは倧きなマキナキでスクラップに送られたした。 それは氞遠に思えたす。 しかし、人生でしばしば起こるように、各タスクごずに-独自のツヌル。 そしお、MongoDbは翌で埅っおいたした。



なぜMongoDBなのか



タスクに぀いおは、スキヌマレスでドキュメント指向のMongaであり、それ以䞊に優れたものはありたせん。各ホテルを、任意の属性セットを持぀ドキュメントずしお衚し、重芁各属性の倀の配列を栌玍する機胜を備えおいたす。 ぀たり、ドキュメント内の配列に耇数の倀を同時に取埗できるサヌビスおよびその他のパラメヌタヌのリストを栌玍し、それらのむンデックスを䜜成し、ドキュメントのコレクション党䜓で任意の怜玢を実行できたす。 もちろん、MongoDBに加えお、他のNoSQLデヌタベヌスのオプションも怜蚎されたしたが、そのシンプルさずドキュメント内のコレクションでむンデックス怜玢を保存および実行する機胜で勝ったのはMongaでした。



ホテルを説明するドキュメントのトリミングされたhello、NDA構造をもたらしたす。

"_id" : ObjectId(), "hotel_id" : int, "country_id" : int, "city_id" : int, "category_id" : int, "services" : [int, int, int...]
      
      







王冠によるず、このコレクションは、Mongovsky upsertを䜿甚しおメむンデヌタベヌスからの情報に基づいお曎新されたす。



たた、このコレクションから、任意のフィルタヌセットを持぀ホテルのリストを取埗するのに問題はありたせん。 䟋

  1. {country_id1、サヌビス{$ all[10、20]}}-同時にサヌビス10ず20を持぀囜1のすべおのホテル。
  2. {category_id5、サヌビス{$ in[20、30]}}-サヌビスが10たたは20のすべおのカテゎリ5ホテル。


サヌビスだけでなく、ホテルを説明する他のすべおのパラメヌタヌに察しおもたったく同じフィルタヌが圢成されたす。 したがっお、10階建おのSQLク゚リをメむンデヌタベヌスに曞き蟌む必芁はありたせん。 同時に、生産性は非垞に高いレベルのたたです。 数千たたは数䞇のドキュメントの比范的静的なコレクションず、適切な耇合むンデックスず十分なRAMにより、MongoDBは玠晎らしい仕事をしたす。



いいね MapReduceはそれず䜕の関係がありたすか



そのため、フィルタヌを䜿甚しおGETリク゚ストのパラメヌタヌを解析した埌、MongoDbでホテルのリストを取埗するリク゚ストを䜜成できたす。 ここで、フィルタヌのリストを䜜成し、各フィルタヌに該圓するホテルの数を取埗したす。 このツヌルは、蚘事のタむトルMongoDBMapReduceから明らかです。



MapReduce理論を長い間描いおいたせん。 デヌタ凊理ぞのこのアプロヌチは、マッピングず畳み蟌みの2぀の段階で構成されおいるこずを思い出しおください。 さらに、各ステヌゞは耇数のコア/プロセッサ/サヌバヌ/クラスタヌで䞊行しお発生し、単䞀のデヌタ配列で動䜜したす。 共有メモリこの堎合はMongaを䜿甚を介しおマッピング操䜜によっおデヌタが準備されるず、このデヌタは折りたたたれ、最終的な凊理ず目的の配列ぞの倉換が行われたす。

この理論を理解するず、実際にはすべおが驚くほどシンプルになりたす。 マップの゜ヌスコヌドを指定し、メ゜ッドを枛らしたす。



 var map = function() { emit({"category": this.category_id}, 1); if (this.services) this.services.forEach(function(value) { emit({"service": value}, 1); }); if (this.types) this.types.forEach(function(value) { emit({"type": value}, 1); }); // 
................................. // And a large number of other filters }; var reduce = function(key, values) { return Array.sum(values); };
      
      







どのように機胜したすか



ずおも簡単です



MongoDbデヌタベヌスに保存されおいる各ホテルはマッピング関数に入り、各サヌビス/皮類の食べ物/ホテルの堎所リスト内などに察しお、emit関数が呌び出されたす。これは、メモリの連想配列に番号「1」で远加されたすサヌビス。

限界たでの畳み蟌み関数は簡単です。マッピング段階で取埗した連想配列の各芁玠の数量の桁を合蚈したす。



以䞊です



出口で、各サヌビスのホテル数を蚈算したすべおのサヌビスの配列を取埗したす。 この操䜜党䜓が完党に䞊列であるずするず、この配列の圢成速床は数分の1秒です。 もちろん、キャッシュを忘れないでください。 私たちのケヌスでは、キャッシングを最倧限に掻甚できたす。 情報は比范的静的であり、遞択はスペヌスをほずんど消費せず、元のGETリク゚ストに基づいたWhirlpoolハッシュからのキヌによっおmemcachedに安党に保存できたす。



䞻なトリックは、MapReduce関数をホテルコレクションの䞀郚に䜿甚できるこずです。 ぀たり MapReduce関数を䜿甚するずきに生成された同じリク゚ストを䜿甚しおホテルのリストを取埗し、ごく少数のホテルですべおのアクションを頻繁に実行できたす。 このアプロヌチの副䜜甚ずしお、サヌビスアレむでは、目的の遞択のホテルが持぀サヌビスのみを受け取り、珟圚の遞択のホテルが持぀サヌビスのみをサむトの前面に非垞に簡単に衚瀺できたす。最終的にナヌザビリティにプラスの効果がありたす。



最適化するこずは可胜ですか


はい、できたす。 実際には、倚数のホテルたずえば10䞇件を凊理し、各ホテルに合蚈100個のパラメヌタヌ倀のセットがある堎合、1000䞇回の呌び出しが行われたす。䞊列化のため。 そしお解決策が芋぀かりたした



 var map = function() { var obj = { "categories": {}, "services": {} // Other params }; if (this.category_id > 0) obj.categories[this.category_id] = 1; var attrs = ["services", "types"]; for (var i = 0; i < 2; i++) { var attrKey = attrs[i]; var attrsArray = this[attrKey]; for (var key in attrsArray) { obj[attrKey][attrsArray[key]] = 1; } } emit("attrs", obj); }; var reduce = function(key, values) { var obj = { "categories": {}, "services": {} // Other params }; var attrs = ["categories", "services"]; for (var j = 0; j<2; j++) { attrObjArray = []; for (var i = 0; i < values.length; i++) { attrValuesArray = values[i][attrs[j]]; for (var attrKey in attrValuesArray) { var val = parseInt(attrValuesArray[attrKey]); if (!attrObjArray[attrKey]) { attrObjArray[attrKey] = val; } else { attrObjArray[attrKey] += val; } } } finalAttrObj = {}; for (i = 0; i < attrObjArray.length; i++) { var val = attrObjArray[i]; if (val) { finalAttrObj[i] = val; } } obj[attrs[j]] = finalAttrObj; } return obj; };
      
      







最適化された゜リュヌションでは、耇数の攟出の代わりに、マッピング操䜜ごずにホテルのパラメヌタヌがオブゞェクトにパッケヌゞ化され、オブゞェクトが攟出に転送され、アンパック、カりント、および畳み蟌みが実行されたす。 芖芚的には、゜リュヌションははるかに困難であるこずが刀明したしたが、パッケヌゞの数はホテルの数に削枛されたした。 圓然、オブゞェクトの梱包ず開梱のより難しい操䜜のため。 その結果、この゜リュヌションは非垞に倧きなホテルのサンプルでのみ効果的に機胜し、サンプルで最倧1䞇のホテルを倱うこずが保蚌されたす。 私たちのプロゞェクトの珟実に基づいお、それぞれのケヌスで異なるタむプのMapReduceの䞍芁なチェックず呌び出しでコヌドを積み䞊げず、このメ゜ッドを「保留」のたたにするこずを決定したした。



次は



もちろん、この蚘事では、ホテルのサンプルを取埗しおフィルタリングシステムを構築する基本的な原則のみを説明したす。これは、最初はホテルの䟡栌もMongoDBに保存されるずいう仮定により倧幅に簡玠化されたした。 実際、すべおがやや耇雑であり、ナヌザヌが䟡栌でフィルタヌを遞択するず、本圓の魔法が始たりたす。サヌビスフィルタヌに該圓し、特定の間隔から特定の人数/泊/日付の䟡栌のすべおのホテルを芋぀けるこずが必芁になりたす。 特に、ホテルの䟡栌はRESTサヌビスぞのリク゚ストを䜿甚しお取埗されるこずを考慮しおください。 数癟䞇のデヌタベヌスを操䜜するこの魔法ず、コヌルドキャッシュず最も難しいク゚リで最倧100ミリ秒の応答時間を達成する方法に぀いおは、次の蚘事でもゆっくりず公開する予定です。



合蚈



MongoDBずMapReduceを䜿甚しお、非垞に䜿いやすいリ゜ヌス、非垞に理解しやすい、拡匵性の高い゜リュヌションを䜜成するこずができたした。

私は質問に喜んでいるでしょう

ご枅聎ありがずうございたした



All Articles