ビッグデヌタを操䜜するための2぀のYandexラむブラリに関する講矩

数週間前、Yandexで、Pythonを䜿甚したビッグデヌタの分析に特化したPyData䌚議が開催されたした。 この䌚議を含め、Yandex分析開発グルヌプの責任者であるVasily Agapitovが話したした。 圌は、MapReduceで蚈算を蚘述しお実行するためず、ログから情報を抜出するための2぀のラむブラリに぀いお話したした。





カットの䞋-デコヌドずスラむドの䞀郚。






私の名前はVasily Agapitovです。デヌタマむニングチヌムを代衚しおいたす。



Yandexでは、ビッグデヌタ、特にMapReduceクラスタヌにあるデヌタを䜿甚しお蚈算を実行したす。 これらは䞻にサヌビスずアプリケヌションの匿名ログです。 さらに、ビッグデヌタ凊理ツヌルを他のチヌムに提䟛しおいたす。 私たちの䞻な消費者は開発アナリストのチヌムです。 簡単にするために、私はそれらをアナリストず呌びたす。



2぀のツヌル、ラむブラリ、それらの倖芳の歎史、およびHadoopの䞖界が倖芳にどのように圱響したかに぀いおお話したす。







甚語のアむデアを同期させたしょう。 デヌタ゜ヌス。 ログに぀いおのみ説明したす。たずえば、ある皮のサヌビスアクセスログを芋おみたしょう。







このログには氎平゚ントリがあり、各゚ントリにはフィヌルドがありたす。vhostはホスト識別子、yandexuidは蚪問者識別子、iso_eventtimeはリク゚ストの日付ず時刻、requestはリク゚スト自䜓およびその他の倚くのフィヌルドです。



䞀郚のフィヌルドのデヌタはすでに蚈算に䜿甚できたす。 他のフィヌルドから、デヌタを最初に抜出しお正芏化する必芁がありたす。 たずえば、リク゚ストフィヌルドにはリク゚ストパラメヌタが含たれたす。 各サヌビスには独自のパラメヌタヌがありたす。 怜玢に最もよく䜿甚されるパラメヌタヌはテキストパラメヌタヌです。 リク゚ストフィヌルドからそれを抜出した埌、それを非垞に倧きくするか、䜕らかの奇劙な゚ンコヌディングを持぀可胜性があるため、正芏化する必芁がありたす。







次に、MapReduceクラスタヌでの蚈算の芳点から蚈算を怜蚎したす。 ご存知のように、MapReduceはサンドむッチ䜜成テクノロゞヌです。 いいえ、これはビッグデヌタ凊理技術です。 慣れおいない堎合、珟圚のレポヌトでは、MapずReduceの2぀の操䜜を䜿甚したデヌタ凊理が含たれおいるこずを知っおおく必芁がありたす。



アナリストのタスクは、ビゞネスロゞックを考慮しお、ログのむベントに関する蚈算を䜜成するこずです。 ラむブラリを䜿甚せずにMapReduceクラスタヌでタスクを解決する堎合、アナリストはどのような困難に盎面するでしょうか たず、MapReduceの操䜜に基づいおビゞネスロゞックを実装する必芁がありたす。 このアプロヌチは、この蚈算のビゞネスロゞックに関連しない蚈算コヌドに远加され、読みやすさずサポヌトを著しく損ないたす。 第二に、最初にログからデヌタを抜出しお正芏化する必芁がありたす-たずえば、リク゚ストフィヌルドからのテキストパラメヌタ。



最初の問題を解決するには 明らかに、クラスタヌぞのナヌザヌアクセスずクラスタヌずの察話を簡玠化する䜕らかの皮類のラむブラリが必芁です。



Hadoopの䞖界では、そのようなラむブラリには、Pig、Hive、Cascadingなどが含たれたす。



YandexはYTず呌ばれるMapReduceの独自の実装を䜿甚したす。この利点は、Habréの蚘事で読むこずができ、デヌタ凊理のための基本的なMapReduce操䜜を提䟛したす。 しかし、残念ながら、YTにはHadoopの䞖界のラむブラリの類䌌物がありたせんでした。 修正する必芁がありたした。



最初に、この問題が発生したずきに、蚈算ごずにマップステヌゞを個別に説明し、ステヌゞを個別に削枛し、クラスタヌで蚈算を開始するこれらのステヌゞ間の関係を個別に説明したした。







さらに、それぞれに独自のランチャヌがありたした。 そのような動物園を維持するこずは非垞に高䟡です。 私たちの解決策は、クラスタヌで蚈算を蚘述しお実行するためのラむブラリであるナむルラむブラリでした。 Pythonを䜜成したずき、䞻にPythonがロヌカルデヌタ凊理に分析を䜿甚するため、Hadoopの䞖界からCascadingのアむデアを取り入れおPython蚀語で実装したした。クラスタヌ䞊の蚈算ずロヌカルデヌタ凊理に1぀の蚀語を䜿甚するず非垞に䟿利です。







Cascadingを知っおいる堎合、Nileでデヌタを凊理するプロセスもおなじみのように思えたす。 クラスタヌ䞊のテヌブルからストリヌムを䜜成、倉曎、グルヌプ化、たずえば、いく぀かのアグリゲヌトを怜蚎し、ストリヌムを耇数のフロヌに分割し、耇数のフロヌを1぀のストリヌムに結合し、他のアクションを実行した埌、結果のストリヌムを必芁なデヌタずずもにテヌブルに保存したすクラスタヌ。



ナむルにはどのようなストリヌム倉曎操䜜がありたすか それらの倚くがありたす、最も䜿甚されるものはここに提瀺されたす。 必芁なフィヌルドのリストを取埗するプロゞェクト。 必芁なレコヌドのみを残しお、フィルタヌからフィルタヌぞ。 Groupby + Aggregateを䜿甚しお、特定のフィヌルドセットでストリヌムをグルヌプ化し、いく぀かの集蚈をカりントしたす。 䞀意、ランダム、および固有の、ランダム、および指定されたレコヌド番号を䜜成したす。 指定されたフィヌルドのセットが等しいこずにより、2぀のストリヌムを結合する結合。 分割しお、いく぀かのルヌルに埓っおストリヌムをいく぀かのストリヌムに分割し、それぞれをさらに個別に凊理したす。 䞊べ替えお䞊べ替えたす。 テヌブルをクラスタヌに配眮したす。



MapおよびReduce操䜜も䜿甚できたすが、本圓にカスタムで耇雑な操䜜を行う必芁がある堎合はほずんど必芁ありたせん。







ナむルの初期化を芋おみたしょう。 圌女はずおもシンプルです。 むンポヌト埌、クラスタヌずゞョブの2぀のオブゞェクトを䜜成したす。 クラスタヌは、どのクラスタヌで実行するか、および他の䟋瀺的な環境を瀺すために必芁です。 ゞョブ-ストリヌムを倉曎するプロセスを説明したす。







ストリヌムを䜜成する方法は ストリヌムは、クラスタヌ䞊のテヌブルから、たたは既存のスレッドからの2぀の方法で䜜成できたす。 最初の2぀の䟋は、クラスタヌ䞊のテヌブルからストリヌムを䜜成する方法を瀺しおいたす。 クラスタヌ䞊のテヌブルぞのパスが匕数ずしお枡されたした。 最埌の䟋は、2぀の既存のストリヌムをマヌゞしおストリヌムを䜜成する方法を瀺しおいたす。



ナむルでのタスクの実装䟋を芋おみたしょう。







アクセスログにより、yandex.com.trホストの蚪問者数を蚈算する必芁がありたす。 アクセスログの様子を思い出しおください。 衚瀺される倚くのフィヌルドのうち、vhostフィヌルドは、yandex.com.trホストに関連する゚ントリのみをフィルタリングしお残し、yandexuidは蚪問者数を蚈算したす。



このタスクのNileコヌド自䜓は次の圢匏になりたす。







ここで、クラスタヌのテヌブルからストリヌムを䜜成し、vhostおよびyandexuidフィヌルドを取埗したす。 vhostフィヌルドの倀がyandex.com.trに等しいレコヌドのみを残し、yandexuidフィヌルドの䞀意の倀の数を考慮した埌、クラスタヌのテヌブルにストリヌムを保存したす。 Job.runは蚈算を開始したす。







クラスタヌで蚈算を開始する前に、Ni​​leは蚈算を䞀連のMapReduce操䜜に倉換したす。 巊偎はナむルに関するストリヌム倉換グラフ、右偎はMapReduce操䜜に関するストリヌム倉換グラフです。 さらに、Nileは蚈算を自動的に最適化したす。぀たり、耇数のMap操䜜が連続しおいる堎合、Nileはそれらをクラスタヌで実行される1぀のMap操䜜に接着できたす。 䜕が起こったのかがわかりたす。 これは非垞に単玔なタスクであり、そのためのコヌドはプログラミング蚀語で芋るのが比范的簡単です。



より耇雑なこずを考えるために、アナリストが盎面する2番目の問題を思い出しおみたしょう。ログからのデヌタを抜出し、正芏化する必芁がありたす。



この問題を解決するこずはどのように決定されたすか 通垞、 ETLはこの問題を解決するために䜿甚されたす。 誰がそれを知っおいたすか 圌は玄30パヌセントを知っおいたす。 誰が知らないかわからないが、忘れおしたったETLは生の生デヌタがあるず仮定し、それらから必芁なレコヌド、フィヌルドなどを抜出し、ビゞネスロゞックを考慮しおそれらを倉曎し、リポゞトリにロヌドしたす。 将来的には、ストレヌゞからのデヌタ、぀たり正芏化されたデヌタに基づいおすべおの蚈算を実行したす。



別のパスを遞択したした。 生デヌタを保存し、蚈算を実行したす。デヌタを抜出しお正芏化するプロセスは、各蚈算で発生したす。



なぜこの方法を遞んだのですか フィヌルドの抜出および正芏化のプロセスで倖郚ラむブラリが䜿甚され、このラむブラリにバグがあったずしたす。 バグを修正した埌、過去の蚈算を再蚈算する必芁がありたす。 このアプロヌチでは、過去の蚈算を実行し、正しい結果を取埗するだけです。 ETLの堎合-このラむブラリがプロセスで䜿甚された堎合-最初にデヌタを再床抜出し、このラむブラリで凊理し、リポゞトリに配眮しおから、蚈算を実行する必芁がありたす。



生デヌタず正芏化デヌタの䞡方を保存できる堎合に適したオプションです。 残念ながら、倧量のデヌタがあるため、これは䞍可胜です。



たず、蚈算ごずに、デヌタの抜出ず正芏化を個別に実行したした。 次に、同じログに察しお、ほが同じ方法で同様のフィヌルドを取埗するこずが倚いこずに気付き、これらのルヌルを1぀のQB2ラむブラリに結合したした。 ルヌル自䜓ぱクストラクタヌず呌ばれ、ログに関するこのようなルヌルのセットは解析されたツリヌでした。







そのため、QB2ラむブラリは生ログぞの抜象むンタヌフェむスを提䟛し、ツリヌの解析に぀いお認識しおいたす。







解析ツリヌを理解したしょう。 これは、Yandexモバむルアプリケヌションのログの解析ツリヌです。 よく芋ないでください、これはグロヌバルマップです。



䞀番䞊はログ゚ントリです。 他のすべおの色付きの長方圢は仮想フィヌルドです。 接続は抜出機胜です。 したがっお、QB2ラむブラリを持たないナヌザヌは、ログフィヌルドにのみアクセスできたす。 QB2ラむブラリを䜿甚するナヌザヌは、ログフィヌルドず、このログに察しおQB2ラむブラリが提䟛するフィヌルドの䞡方を䜿甚できたす。



このラむブラリの利点を具䜓的な䟋で芋おみたしょう。 問題を怜蚎しおください。 10321に等しいAPI_keyフィヌルドの倀で識別されるYandexモバむルアプリケヌションがあるずしたす。フィヌルド、特にJSONオブゞェクトの圢匏で蟞曞を含むevent_valueフィヌルドにログを曞き蟌むこずがわかりたす。 この蟞曞のステヌゞキヌの意味に興味がありたす。



むベントの日付ごずに分解しお、各ステヌゞの蚪問者数を蚈算する必芁がありたす。 QB2ラむブラリはこれにどのようなフィヌルドを提䟛したすか たず、API_key、アプリケヌション識別子。 次に、device_id、ナヌザヌID。 最埌に、むベントの日付であるevent_dateは、ログ゚ントリから盎接取埗されるのではなく、かなり倚数の倉換によっお取埗されたす。 QB2ラむブラリを䜿甚しないず、このフィヌルドが必芁な各蚈算で手動倉換を実行する必芁がありたす。 同意したす、これは䞍䟿です。



さらに、event_valueフィヌルドずステヌゞ倀が必芁です。 それらはツリヌでは解析されたせん。これは論理的です。なぜなら、それらは1぀の特定のアプリケヌションに察しおのみ曞かれおいるからです。



゚クストラクタヌを䜿甚しお、解析ツリヌを次のフォヌムに远加する必芁がありたす。 このタスクの初期化はどのように倉わりたすか さらに、゚クストラクタヌずフィルタヌをむンポヌトしたす。 event_valueおよびステヌゞ倀を取埗するには、゚クストラクタヌが必芁です。 フィルタヌ-レコヌドをフィルタヌし、必芁なものだけを残したす。







前の䟋ではナむルからのフィルタリングを䜿甚しおいたしたが、なぜこの䟋ではQB2ラむブラリからのフィルタリングを䜿甚したのでしょうか QB2は、Nileず同様に、蚈算の最適化を詊みたす。぀たり、フィルタリングで䜿甚されるフィヌルドの倀をできるだけ早く取埗しようずしたす。 他の仮想フィヌルドの倀よりも早い。



なぜこれが行われるのですか レコヌドがフィルタリング条件を通過しない堎合、残りの仮想フィヌルドの倀を取埗しないようにしたす。 したがっお、コンピュヌティングリ゜ヌスを倧幅に節玄し、クラスタヌでの蚈算を高速化したす。







蚈算コヌド自䜓は次の圢匏になりたす。 ここでは、クラスタヌのテヌブルからストリヌムを䜜成し、QB2挔算子でストリヌムを倉曎したす。これは、解析ツリヌの名前この堎合はログの名前ず䞀臎し、フィヌルドずフィルタヌのセットず䞀臎したすで初期化したす。



フィヌルドには、API_key、device_id、event_dateフィヌルドを名前でリストしたす。これは、QB2ラむブラリがこれらのフィヌルドを取埗する方法をすでに知っおいるためです。



event_valueフィヌルドを抜出するには、暙準のjson_log_field抜出プログラムを䜿甚したす。 圌は䜕をしおいたすか 枡された名前で、察応するログフィヌルドから倀を受け取り、JSONオブゞェクトずしおロヌドしたす。 このロヌドされた倀をevent_valueフィヌルドに保存したす。



ステヌゞ倀を取埗するには、別の暙準゚クストラクタヌdictItemを䜿甚したす。 圌に枡されたキヌ名ずフィヌルド名を䜿甚しお、このキヌのこのフィヌルドから察応する倀を抜出したす。



フィルタリングに぀いお。 device_idフィヌルド倀が定矩され、アプリケヌションに関連するレコヌド、぀たりapi_keyフィヌルド倀が10321であるレコヌドにのみ関心がありたす。QB2挔算子を適甚した埌、ストリヌムには次のフィヌルドがありたすapi_key、device_id、event_date、event_value、stage。



結果のストリヌムを次のように倉曎したす。 event_dateフィヌルドずstageフィヌルドのペアでグルヌプ化し、䞀意のdevice_id倀の数を蚈算したす。 この倀をusersフィヌルドに入れ、その埌、結果のストリヌムをクラスタヌに保存したす。 Job.runは蚈算を開始したす。







蚈算が完了するず、クラスタヌには次の圢匏のテヌブルがありたす。event_dateフィヌルドずstageフィヌルドの各ペアに぀いお、䞀意のナヌザヌ倀の数はusersフィヌルドにありたす。 したがっお、QB2ずNileラむブラリの統合により、私が衚明した䞡方の問題が解決されたす。 ご枅聎ありがずうございたした。



All Articles