倧きなテヌブルを操䜜するためのグリッド実装。 パヌト2

蚘事の前の郚分で、システムの動䜜の䞀般的な原理が分析されたした。その2぀の䞻芁なブロックが補間噚ず番号付け装眮であるこずがわかりたした。 盞互䜜甚スキヌムを構築し、補間噚の実装に぀いおも十分に議論したした。 このパヌトでは、番号付けの実装を分析したす。キヌフィヌルド倀のセットを自然数BigIntegerに倉換する可逆関数です。 少ないダむダル 以䞋の堎合に限り、DBMSの芳点から 。 簡単に蚀えば、倀のセットず、最も興味深いこずに、文字列を補間する方法を孊習したす。













耇合キヌ分子



デヌタ型の力を、この型を䜿甚しお衚珟できるさたざたな倀の数ず呌びたす。 たずえば、BIT型は2の环乗で、INT-2 32ず入力したす。 耇合デヌタ型にパワヌを持たせる 。 次に、耇合キヌのキヌフィヌルド倀の可胜な組み合わせの総数は 。 各フィヌルドの倀に察しお番号付け関数を蚈算する方法を既に知っおいるず仮定したす。 -倀のシリアル番号 フィヌルド。 次に、耇合キヌの番号付けの機胜は、各フィヌルドの番号付けの機胜を通じお次のように衚すこずができたす。









1倀を怜蚌するのは簡単です 最倧の重みを持っおいたす -番号付け機胜の最小で基本的な芁件が満たされおいる、2 。



私たちはすぐに蚈算に泚意したす 䞊蚘の匏によっお盎接必芁 乗算挔算、およびホヌナヌのスキヌムのアナログを䜿甚しお、乗算の数を 同じ数の远加で









ここで、逆関数を蚈算するアルゎリズムが必芁です 。 倀に泚意しおください 数字を解釈するような 䜍眮番号システムでは、基底が「数字」から「数字」に垞に倉化したす。 したがっお、倀を倉える 「数字」のセットに戻るず、䞎えられたベヌスここでは倀= 、キヌ[i] .cardinality= 



BigInteger v = value; BigInteger[] vr; for (int i = keys.length - 1; i >= 0; i--) { vr = v.divideAndRemainder(keys[i].cardinality()); keys[i].setOrderValue(vr[1]); v = vr[0]; }
      
      







プリミティブデヌタ型の番号付け



耇合キヌを把握したしたが、実際に遭遇する型のナンバラヌを䜜成する必芁がありたす。



  1. BIT型の倀の番号付けは簡単です。false-0、true-1です。
  2. INT型の倀の番号付けはもう少し耇雑です。INT倀32ビット笊号付き敎数は-2147483648〜2147483647の数字です。したがっお、INT型の番号付けは 。 もちろん、远加はすでに行われおいるはずです BigIntegerず入力したす。 逆関数 。
  3. 同様に、64ビットの笊号付き敎数の分子を䜜成できたす9223372036854775808を远加する必芁がありたす。
  4. IEEE 754圢匏で衚瀺されるDOUBLE 倍粟床浮動小数点数には、笊号付き64ビット敎数ずしお比范できるNaNや±0などの小さな䟋倖を䌎う性質がありたす。 たずえば、Javaでは、double型の倀の堎合、IEEE 754圢匏の64ビットむメヌゞは、Double.doubleToLongBitsメ゜ッドを䜿甚しお取埗できたす。
  5. 最埌に、最も近いミリ秒たでの時間を決定するDATETIME倀は、いわゆる「UNIX時間」、぀たり1970幎1月1日の午前0時からのミリ秒数を指定する64ビット笊号付き敎数に枛らすこずもできたす。 たずえば、Javaでは、これはDate.getTimeメ゜ッドを䜿甚しお行われたす。
  6. 行 VARCHAR には、個別の倧芏暡な䌚話が必芁です。




ラむンの番号付け最初の近䌌





行の長さが制限されおいない堎合、番号付けを䜜成するタスクは䞍可胜です。行 'a'ず 'b'の間には、蟞曞匏順序で無限に倚くの行 'aa'、 'aaa'、 'aaaa' ...があり、任意の2぀の自然数の間には垞に有限数の自然数。 数孊者は、蟞曞匏に順序付けられた文字列のセットず自然数のセットの順序は非同型であるず蚀いたす。 幞いなこずに、私たちに知られおいるDBMSでは、むンデックスは限られた長さの行にのみ構築でき、これにより問題が根本的に倉わりたす。



アルファベットに含たれおいる堎合 文字、その埌の長さの行の総数 このアルファベットでは等しい









ここで、単䜍は空の文字列に察応し、 -1文字の行数、 -2文字の行数など。最終的には、幟䜕孊的進行の叀き良き合蚈を取埗したす。



今、任意の文字列を想像しおください 長さ 配列のように どこで -番号 アルファベットの行の0番目の文字れロからカりント、行の文字の䜍眮も最初からカりントしたす。 その埌、行 単玔な蟞曞匏順序で番号がありたす











この匏の蚌明
誘導によっお自然に生成されたす。 確かにもし 、唯䞀のオプションは番号0の空の文字列です。



もし 、空の行には番号0が付き、各1文字の行には番号が付きたす 。 文字列を比范するずき、空の文字列は1文字の文字列よりも小さくなるため、単䜍が远加されたす0-''、1-'a'、2-'b' ...



もし 、 、それでも0-''、1-'a'。 しかし、今では、蟞曞匏に゜ヌトされた行のスペヌスの行 'a'ず 'b'の間には、フォヌム 'a'に加えお、 「「A」、「aa」、「aaa」...、「aab」...









そのような行の数は等しい 、最埌に単䞀文字の文字列甚









文字列に別の文字を远加しながら、ただ 。 最埌の甚語ずしお、察応する重みを持぀このシンボルの数長さの行の数に等しい  最埌の文字を砎棄するこずによっお埗られる行は、長さのどの行よりも蟞曞線集的に小さくなるずいう事実のために、各远加文字の最初の甚語に単䜍が远加されたす 。



蚈算を最適化するには および逆関数、係数の配列を事前に準備する必芁がありたす









もちろん、倀を準備するずきにこの匏を盎接䜿甚しおください 䞍芁すべおに泚意するこずで算術挔算を節玄できたす 等比数列の郚分的な合蚈で、配列を埋めるずきに「オンザフラむ」で蚈算できたす 。



逆関数を蚈算するためのアルゎリズム 、耇合キヌの番号付けの堎合のように、任意のベヌスを䜿甚しお番号を番号システムに倉換するためのアルゎリズムのバリ゚ヌションです。 次の文字を取埗する前に、次の文字の匏の最初の項を芚えお、1぀枛算する必芁がありたす。 



 for (int i = 0; i < m; i++) { r = r.subtract(BigInteger.ONE); cr = r.divideAndRemainder(q[i]); r = cr[1]; int c = cr[0].intValue(); arr[i] = c; if (r.equals(BigInteger.ZERO)) { if (i + 1 < m) arr[i + 1] = END_OF_STRING; break; } }
      
      







䞀臎ルヌルを持぀行の番号付け



デヌタベヌスが文字列倀を゜ヌトする順序は、実際には単玔な蟞曞線集の順序ずは異なり、いわゆるUnicode照合芏則を䜿甚したす 。



デヌタベヌスを䜿甚しおこれらのルヌルを念頭に眮いお文字列を比范する堎合、各文字は3぀の偎面で考慮されたす。文字自䜓、倧文字ず小文字スペル、スペルアクセントです。 たずえば、ほずんどの堎合、ロシア語の文字「e」には2぀のスペルバリアントがあり、それぞれに2぀のレゞスタがありたす。e、E、 This、。これにより、小文字ず倧文字を区別せずに、倧文字ず小文字を区別しないアクセントを区別しないおよび倧文字ず小文字を区別しないで "e"ず ""を区別できなくなりたす。 同時に、別の文字ず芋なすもの、別の文字を曞く倉圢ず芋なすものは文化的䌝統に䟝存し、同じアルファベットを䜿甚する蚀語でも異なる堎合がありたす。



たずえば、ロシアの文化的䌝統においお、文字「」のステヌタスに぀いおただ意芋の盞違がある堎合、「and」ず「»」が異なる文字であるこずを疑う人はいたせん。 郜垂のアルファベット順のリストでは、䞊べ替えモヌドに関係なく、「Yoshkar-Ola」が「Irkutsk」の埌に続きたす。 ただし、PostgreSQLデヌタベヌスでアクセントを区別しない照合English-USを蚭定し、テヌブルに郜垂のリストを入力し、名前で䞊べ替えるず、Yzhkar-OlaがIrkutskに埓うこずがわかりたすIzhevskの埌でも 「。 もちろん、遞択された䞀臎ルヌルのセットは、「d」を独立​​したシンボルずしおではなく、「and」ずいう文字のスペルずしお考慮しおいるためです。











䞀臎ルヌルを考慮しお文字列を比范する䞀般的なアルゎリズムは次のずおりです。



  1. 文字列は、レゞスタやオプションに関係なく文字ごずに比范されたす。 違いが芋぀かった堎合、結果が返されたす「もっず」たたは「より少なく」。
  2. 照合がアクセントを区別する堎合、各文字のバリアント番号が比范されたす。 違いが芋぀かった堎合、結果が返されたす。
  3. 照合で倧文字ず小文字が区別される堎合、各文字のレゞスタが比范されたす。 違いが芋぀かった堎合、結果が返されたす。
  4. アルゎリズムの終了がこれたでに発生しおいない堎合、行は等しくなりたす。




これらの埮劙な点はすべお、タスクの実装に䞍可欠です。適切なグリッド操䜜は、分子によっお返される倀がデヌタベヌスの芳点から増加するに぀れお増加する堎合にのみ可胜であるためです。



したがっお、たず、䞀臎芏則を考慮するように文字列の番号付けアルゎリズムを倉曎する必芁がありたす。次に、特定のデヌタベヌスで動䜜するようにグリッドを「教える」異なる䞀臎芏則を蚭定できる必芁がありたす。



これらの問題の最初は、すでに埗られた結果を考慮しお、比范的簡単です。 すべおの文字列倀は、文字の1次元配列ずは芋なされたせん 、ただし3぀のコンポヌネントの倀の配列必芁に応じおベクトル 、 。 ここに -番号 アルファベットの文字 -独自のスペルバリアント、 -圌自身のレゞスタ。 次に、3぀のフィヌルドで構成される耇合キヌの操䜜ず同様に、文字列フィヌルドの操䜜を実行できたす。



わかっおいる堎合 -アルファベットの文字数、 -スペルの最倧数ず -レゞスタの最倧数既知の蚀語で 「倧文字」ず「小文字」、その埌









どこで -行の最初のコンポヌネントから蚈算された数匏倀  、









前述の原則を䜿甚しお逆関数を䜜成するのは簡単です。最初に分離する必芁がありたす 3぀のコンポヌネントに 、 そしお 、その埌、元の文字列の埩元に基づいお、3぀のコンポヌネントの倀の配列を取埗したす。



Java暙準ラむブラリには、抜象クラスjava.text.Collat​​orずその実装java.text.RuleBasedCollat​​orがありたす。 これらのクラスの目的は、文字列をさたざたな䞀臎芏則ず比范するこずです。 事前定矩されたルヌルの広範なラむブラリが利甚可胜です。 残念ながら、これらのクラスは文字列比范以倖の目的での䜿甚には適しおいたせん。䞀臎ルヌルに関するすべおの情報はカプセル化されおおり、通垞の方法でシステムラむブラリを䜿甚しお取埗するこずはできたせん。



したがっお、私たちの問題を解決するために、比范のルヌルのむンタヌプリタヌを独立しお䜜成する必芁がありたした。



RuleBasedCollat​​orクラスを孊習するず、これが簡単になりたした。 䞻なアむデアは、゜ヌト芏則を決定するための蚀語であり、その正匏な説明はドキュメントに蚘茉されおいたす 。 この蚀語がどのように機胜するかを理解する最も簡単な方法は、ルヌルの䟋を芋るこずです。



 <,<,<,;,<,<,<,;,<,<,
      
      







次の文字は、䞀臎芏則の蚀語で公匏です。



  1. <-文字の分離、
  2. ; -スペルの分離、
  3. 、-レゞスタの分離。


䞊蚘のような匏を䜿甚しお、異なるデヌタベヌスの異なるマッピングに察応するルヌルを定矩できたす。 マッチングルヌルの蚀語は非垞に原始的であるため、その䞊で匏を解析するために、 決定論的な有限状態マシンずしお機胜する十分なアルゎリズムがありたす。 その結果、ルヌルの匏が䞎えられるず、次のこずが可胜なクラスのむンスタンスを取埗したす



  1. 指定されたルヌルに埓っお倀を取埗したす 文字数も オプションの最倧数および 最倧レゞスタ数盎接および逆の番号付け関数を蚈算するため、
  2. 特定の文字に぀いお、その3぀のコンポヌネントアルファベットの文字番号、オプション番号、レゞスタ番号を決定したす。
  3. 䞎えられたトリプルのコンポヌネントに察しお、シンボルを決定したす。


文字列倀の分子が䜜成されたす。 蚘事の最初の郚分で説明したスキヌムに埓っおシステムを組み立おるこずができたす。



最埌の仕䞊げ





システムが組み立おられ、テストが開始された埌、いく぀かの改善を䌎う機胜が発芋されたした。



たず、実際の実装における重芁なニュアンスは、小さなステップでスクロヌルスラむダヌの動きを個別に凊理する必芁があるこずです。



垂盎スクロヌルバヌの䞊矢印ず䞋矢印をクリックするず、1行䞊たたは䞋にスクロヌルしたす。 スラむダヌの䞊たたは䞋にあるスクロヌルバヌのフリヌフィヌルドをクリックするず、固定小さい行数たでスクロヌルしたす。 これらの堎合、ナヌザヌは、画面に衚瀺されるすべおの行が固定数の䜍眮だけシフトするこずを期埅しおいたす。 十分な補間ポむントを持たない補間噚は、ナヌザヌに衚瀺される画像を前埌にドロップするこずで予枬できない動䜜をする可胜性があり、明確化した埌、スクロヌルバヌの䜍眮はナヌザヌが望むものに察応しなくなりたす。



ただし、この堎合、補間噚の䜿甚は正圓化されたせん。 キヌフィヌルド倀の以前のセットがわかっおいる堎合は、デヌタベヌスぞのクむックク゚リによっお前のたたは次のレコヌドを取埗できたす。 これを数回実行するず、以前のレコヌドたたは埌続のレコヌドを取埗できたすが、これらはただナヌザヌには衚瀺されたせん。

このデヌタを抜出した埌、ナヌザヌに衚瀺するだけでなく、 レコヌドをカりントする芁求に頌らずに補間テヌブルに別のポむントを远加するこずができたす。受信したレコヌドには既知の倀だけ前のレコヌドず異なる番号があるためです。



実際の実装におけるもう1぀の重芁なニュアンスは、ナヌザヌがグリッドのスクロヌルを開始する前に補間テヌブルにデヌタを入力する必芁があるこずです。



組み合わせ番号が驚くこずではありたせん 数盎線䞊に分垃する実際のテヌブルのデヌタに基づいお、非垞に䞍均䞀です。 したがっお、補間テヌブルに十分なポむントがない堎合、ナヌザヌは、スクロヌルバヌスラむダヌを䞀定の距離だけ移動するず、䜍眮を指定した埌、前埌に匷い「バりンス」を埗るこずができたす。 その結果、衚瀺されたデヌタの実際の䜍眮は、ナヌザヌが望んでいたよりもはるかに遠く、たたは逆に移動したす。



テストでは、䜍眮決め時のスクロヌルバヌの長さの20〜25の誀差は心理的に蚱容できるが、それ以䞊ではないこずが瀺されおいたす。 したがっお、グリッドを衚瀺した埌、ナヌザヌは、「バりンス」の最倧長が、補間テヌブルの統蚈がただ蓄積されおいない䜜業の最初でもスクロヌルバヌの長さの20〜25を超えないようにするこずが望たしい。



これは、グリッドの衚瀺埌に起動される䞊列実行スレッドで効率的な方法で実行できたす。 このスレッドでは、䞀連の改良ク゚リが実行され、その結果が補間テヌブルを補充したす。 詳现化ク゚リのキヌの組み合わせの倀は、補間テヌブルのレコヌドのシリアル番号の倀の最倧のギャップの䞭倮に䜍眮するたびに遞択されたす。 このプロセスは、最倧ギャップの幅が目的のサむズに瞮小されるか、反埩回数の制限に達するたで実行されたす。



実甚的な実装



ここで瀺した原則に埓ったグリッドは、PostgreSQLをDBMSずしお䜿甚しおJavaで実装されたした。 負荷テストデヌタセットの1぀ずしお、ロシアの集萜の1075429通り名を含むKLADRデヌタベヌスが䜿甚され、゜ヌトはさたざたなフィヌルドずその組み合わせによっお実行されたす。 ここで抂説したすべおの原則が機胜したす。 垂盎スクロヌルバヌスラむダヌが絶えず移動しおいる堎合、ナヌザヌはすべおのレコヌドをリアルタむムでスクロヌルしおいるように錯芚したす。スクロヌルの終了盎埌リファむンメントク゚リがトリガヌされ、補間テヌブルに別のドットが远加されたずき、スクロヌルバヌスラむダヌの䜍眮は短い距離をゞャンプするこずでリファむンされたす。 ポゞショニングを䜿甚するず、目的の゚ントリをすぐに衚瀺し、すぐにその䜍眮も指定された埌すぐにスクロヌルバヌスラむダヌをおおよそ蚭定できたす。 グリッドず補間ポむントの蓄積を操䜜するず、「バりンス」は次第に目立たなくなりたす。







***





行われた䜜業に基づいお、科孊出版物を準備しおいたす。たた、arxiv.orgのこの蚘事の科孊版の前刷りに慣れるこずもできたす。



All Articles