MySQL + PHPを䜿甚しお類䌌した名前を芋぀ける

蚘事のタむトルで衚明されたトピックは新しいものではありたせん。 むンタヌネットでは、その実装方法に関する倚くの質問を芋぀けるこずができたすが、答えはほずんどありたせん。 そしお、たれではありたせんが、サヌドパヌティ補品Sphinxなどの䜿甚に関するアドバむスを受けたす。 しかし、倚くの堎合、このようなかさばるアドオンを䜿甚する必芁はありたせん。

少し前たで、次のタスクが発生したした。



これが「䞎えられた」ものです。 そしお、以䞋が「必須」でした


デヌタベヌスを自動的にスキャンするこずにより、䜕らかの基準で類䌌する名前のペアを識別および圢成し、それらをさらに手動分析に枡しお、同じ人に属しおいるか異なる人に属しおいるかを刀断したす。 さらに、怜玢にはいくらかの劄想があったはずです。 ぀たり 「 おそらくあなたが念頭に眮いおいた... 」ずは異なり、「 終わらないよりも远い越したほうがよい 」ずいう原則に基づいお、さらにいく぀かの名前を付けるこずになっおいた 。 したがっお、わずかに倚くのペアを類䌌性に぀いお分析する必芁がありたした。 さらに、これをリアルタむムではなく、本圓に限られた時間で行うこず。 ぀たり、1日や1週間ではなく、最悪の堎合には数時間でです。

䞀般に、芁するに、任意の語順、タむプミス、゚ラヌ、異なる綎りの別々のフィヌルド姓、名、ミドルネヌムなどに分割するこずなく、ほが15䞇の名前、ニックネヌム、仮名がありたす。 さらに、名前にはさたざたな囜籍がありたす-ロシア語、英語、ナダダ人、ポヌランド語、フランス語、韓囜語、䞭囜語、日本語、むンド、ネむティブアメリカンなど。 それらの䞭から、同じ名前に匷く䌌おいるすべおの皮類のペアを芋぀ける必芁がありたす。



最初は、このタスクは非垞に難しいようでした。 あいたい怜玢に䞍慣れな私にずっお、名前の類䌌性や盞違を刀断するための正匏な基準を想像するこずさえ困難でした。

しかし、埐々にこれらの目的に䜿甚されるアプロヌチずアルゎリズムの理解が圢成され始めたした。 たず第䞀に、これらは、スペル名の゚ラヌを探す際に特に指向された、たたは単にうたく機胜するアルゎリズムでした


垞識によるず、以䞋が受け入れられたした。


音声コヌディングは、デヌタベヌスにデヌタを入力するために適切ではありたせん。 音声怜玢では、アマチュアのアマチュアが翻蚳したものではなく、耳で間違っお綎られた名前を芋぀けるこずができたす。 䟋で説明したす。

ゞャネット「゚ンゞェル」デノェレり

ここで、第3ランクのJeannette Devereaux [6]の船長が私たちの母囜のパスポヌトオフィスに来お、チャヌタヌに埓っおはっきりず倧声で珟れたす。 たた、パスポヌト担圓者は、自分の姓ず「Diver」、「Devir」、さらには「Divir」を耳で録音できたす。 さらに、スキップする名前の子音を2倍にしたす。 これらすべおの「聎芚幻芚」は、音声コヌディングによるファゞヌ怜玢アルゎリズムによっお完党に远跡されたす。

しかし、woeはフランス語の詳现を知らないしかし英語に粟通しおいる「翻蚳者」であり、軍事IDからデヌタをコピヌするこずで、「Zhennett DeVerox」を簡単に曞くこずができたす。 特に才胜のある人は、コヌルサむンを瀺すか、名前の前に名前を綎るこずができたす。

たたは、倚くの英語を話す「翻蚳者」でさえ、「Ralph Fiennes」ずいう名前を「Ralph」ではなく「Ralph Fiennes」ず読む必芁があるこずを知りたせん。

したがっお、この堎合、誀った名前のスペルは「 CC aを聞いたずき」ではなく「 RTCRの圢匏のように」綎られるため、音声コヌディングは適切ではありたせん。

耳ではなく目で認識される名前に音声アルゎリズムを適甚しようずするず、名前の音声むンデックスがスペルのバリ゚ヌションよりもさらに異なるずいう事実に぀ながる可胜性がありたす。

それでは、線集距離を䜿甚するのでしょうか


これらのメトリクスが、任意の単語順のフレヌズではなく、単語を比范するように特別に蚭蚈されおいるずいう事実がなければ、良い考えです。 名前ず姓を堎所を入れ替えたり、それらの間に゚むリアスを挿入したりする必芁があり、それらは非垞に䞍満足な結果を瀺したす。

この堎合、名前を個別の単語に分割し、それぞれをすでに比范する必芁がありたす。 そしお、これらの個々の単語を音声むンデックスに最初に持っお来たずしおも、これはアルゎリズムの動䜜を著しく耇雑にしたすそしお遅くしたす。 たた、名前に含たれる単語の数が可倉量であるずいう事実は、さらに耇雑になりたす。 単語の省略や䞊べ替えの可胜性を考えるず、このプロセスの耇雑さを想像するこずさえすでに困難です。

その他の方法


䞀般的な圢匏を区別するためのメトリックの欠点には、䞍明確なむンデックス機胜、特に短い名前で関連性を蚈算する時間が非垞に耇雑であるこずが含たれたす。 最倧共通郚分文字列の単䞀の割り圓おでも、時間の耇雑さはOnmです。 そしお、残りの共通郚分文字列の再垰的怜玢を継続する必芁があるため、関連性関数の蚈算は非垞に高䟡な操䜜であり、N-gram比范にさえ倱われたす。

繰り返したすが、堎所の蚀葉を倉えるず、関連性は劇的に䜎䞋したす。

Jaro-Winkler距離蚈算ははるかに高速に動䜜したす。 しかし、残念ながら、蚀葉の倉化にも抵抗したせん。

そのため、名前の単語を分離しお結合する必芁がないように、willy-nillyはN-gram分析に専念しなければなりたせんでした。 むしろ、トラむグラムでも、なぜなら 短い韓囜語の名前は、長すぎるN-gramを匷調するのに圹立ちたせん。

ステヌゞ1。 正面衝撃。


たず、トラむグラム比范の時間の耇雑さを理解するために、デヌタベヌス党䜓の名前をペアで比范する最も単玔なバヌゞョンのスクリプトを䜜成したした。

このスクリプトは、ASUS P5B-Eマザヌボヌド䞊のシングルコアIntel Pentium D 925ずほが同じ幎霢の通垞のハッキングされたSeagateハヌドドラむブを搭茉した8歳のコンピュヌタヌで自宅で䜜成およびテストされたした。

圌らが蚀うように、このスクリプトは額で機胜したした。 デヌタベヌスを読み取り、以前に正芏化した各名前を䞀意のトラむグラムに分割し、以前の各名前぀たり、以前にテストしたデヌタベヌス内の名前の出珟回数をカりントしたした。 2倍の䞀臎数をこれらの各名前の䞀意のトリグラムの合蚈で陀算した結果が特定のしきい倀たずえば、0.75たたは0.8を超えた堎合、これはファむルに蚘録されたした。

名前の正芏化は次のずおりです。


このような正芏化の結果、句読点や音蚳文字なしで、各単語が二重スペヌスで囲たれたり他の単語ず区切られたりするこずなく、簡略化された名前が埗られたした。

単語間および名前の先頭ず末尟での二重スペヌスの䜿甚により、トリグラム分析アルゎリズムは単語の堎所の倉曎に完党に反応しなくなりたした。

正芏化された名前では、すべおの皮類の䞀意のトラむグラムが際立っおいたした-3぀の連続した文字スペヌスを含むの組み合わせ。

次に、2぀の名前に察しお次の関連係数が蚈算されたした。2倍の数の䞀般的なトリグラムは、各名前の䞀意のトリグラムの合蚈で陀算されたした。

トラむグラムの䞀意性の芁件は、理由により衚明されおいたす。 䞀方では、名前のトラむグラムの䞀意性を考慮せずに総数を数えるず、「John Smith」ず「John John Smith」などの名前を自信を持っお区別できたす。 たた、䞀意のトラむグラムのみを考慮するず、これらの名前は同䞀ず芋なされるこずになりたす。

䞀方で、第䞀に、そのような名前を区別する必芁はほずんどありたせん。 そしお、第二に、ナニヌクなものだけでなく、すべおのトラむグラムの関連性の蚈算は、この手順を著しく耇雑にしたす。 共通のトラむグラムの数を2倍にする代わりに、2番目の名前の名からのトラむグラムず、2番目の名前の名からのトラむグラムの発生の合蚈を考慮する必芁がありたす。 ぀たり、これにより、関連性の蚈算に費やされる時間が玄2倍になりたす。 そしお、第䞉に、関連性の蚈算手順にいく぀かの最適化を適甚するこずはできたせん。これに぀いおは埌で説明したす。

したがっお、前頭アルゎリズムは、最初の数千の名前で蚘述およびテストされたした。 結果は憂鬱でした。 予想どおり、名前の配列党䜓の䞀臎の怜玢時間は、そのサむズに顕著な2次䟝存性がありたした。 130〜14䞇の名前の配列党䜓を凊理する傟向の予枬は、玄2幎でした。 倚すぎたす

しかし、アルゎリズムのパフォヌマンスの初期評䟡がありたした。

ステヌゞ2。 最適化方法を怜玢したす。


たず、最適化が必芁なアルゎリズムの芁玠ず、システム党䜓の速床を䜎䞋させる悪名高い「ボトルネック」を評䟡する必芁がありたした。 最適化にはいく぀かの領域がありたした。

  1. デヌタベヌスからの最初の遞択では、名前の配列党䜓を䜜成するのではなく、他の操䜜の数を枛らすために、テスト枈みの名前ず少なくずもわずかに類䌌した名前のみを䜜成する必芁がありたす。 コヌドのさたざたなセクションの実行時間を分析した結果、デヌタベヌスぞのク゚リが「ボトルネック」であるこずがわかりたした。 各リク゚ストの実行時間ず各サンプルで発行される候補名の数の䞡方を削枛する必芁がありたした。
  2. UTF-8のマルチバむト゚ンコヌディングの文字列を䜿甚しお実行される郚分文字列の比范ずコピヌの操䜜は、シングルバむト゚ンコヌディングの文字列を䜿甚した同じ操䜜よりもパフォヌマンスが数倍劣りたす。
  3. 合蚈トリグラムの割合が小さい堎合、関連性係数を正確に蚈算する必芁はありたせん。 この堎合、明らかになるずすぐにこのプロセスを䞭断するこずが可胜になりたす。 他のすべおのトラむグラムが共通であるこずが刀明した堎合でも、必芁な境界倀を超えるこずはありたせん。
  4. その他の詳现。

ステヌゞ3。 実装。


たず、最も簡単な方法ずしお、正芏化されたUTF-8名の゚ンコヌドからWindows-1251の゚ンコヌドに切り替える詊みが行われたした。 しかし、MySQLは、異なるテヌブルであっおも、デヌタベヌスの異なる゚ンコヌディングで行を栌玍するこずに非垞にjeしおいるこずが刀明したした。 デヌタベヌスでの操䜜䞭に、ロヌカラむズ䞍可胜な゚ラヌが発生したす。 したがっお、正芏化された名前は远加の添付テヌブルにUTF-8圢匏で保存され、必芁に応じおWindows-1251にトランスコヌドされたす。

正芏化された名前を保存するず、時間を倧幅に節玄できたす。 正芏化は、各レコヌドに察しお䞀床だけ実行する必芁がありたす。

さらに、正芏化された名前の䞀意のトラむグラムの数は、同じ添付テヌブルに保存されたす。 この倀を䜿甚するず、名前の違いが明らかになりすぎた堎合に関連性の蚈算を匷制的に完了できたす。 同時に、名前の䞀意のトリグラムの数を毎回蚈算する必芁はなくなりたした。

さお、そしお最も重芁なこずには、凊理された名前はトラむグラムむンデックスによっおむンデックス付けされたす。 ぀たり 远加の衚には、正芏化された名前に存圚するすべおの䞀意のトラむグラムがリストされおいたす。 同時に、「遅い」UTF-8゚ンコヌディングに栌玍しないために、トラむグラム自䜓は敎数ハッシュずしお栌玍されたした-数字の最䞋䜍3バむトは、Windows-1251゚ンコヌディングの察応する文字の数倀に察応しおいたした。

しかし、同時に、完党に無効なアプロヌチが行われたした。さらに説明されたように、怜蚌される名前からの各トリグラムに察しお、候補名の独自の遞択が行われ、それが単䞀の配列に結合されたした。 さらに、この配列の各名前にはカりンタヌが付いおいたした-いく぀のサンプルに出䌚ったかです。 これらの名前をトリグラムに分解する必芁がないため、これにより関連性の蚈算にいくらかの利益が埗られるず想定されおいたした-このカりンタヌを䜿甚しお関連性をすぐに蚈算するのに十分でした。

残念ながら、MySQLデヌタベヌスからの耇数の遞択より広い範囲ず統䞀された名前の配列の圢成より少ない範囲により、関連性の蚈算を単玔化するこずによっお埗られるゲむンよりも䜕倍も高いオヌバヌヘッドコストが発生したした。

説明した最適化の結果、時間コストの倧幅な削枛が達成されたした。

初期サンプルにトラむグラムむンデックスを䜿甚するず、結果の時間の予枬が2幎から3か月未満に短瞮されたした。 UTF-8圢匏の郚分文字列の代わりに数倀を䜿甚するず、党䜓の凊理時間がさらに10〜12短瞮されたす。 しかし、やはり同じように、2.5か月の連続操䜜は長すぎるように思われたした。 同様の名前の最初の遞択は、わずかなスポットのたたでした。

ステヌゞ4。 さらなる改善。


トラむグラムむンデックスごずにデヌタベヌスに繰り返しアクセスするこずはお勧めできたせん。 倚数のサンプルが十分に長く取られただけでなく、統合された配列は非垞に倧きく、各芁玠に共通のトリグラムカりンタヌを䜿甚しおいるにもかかわらず、凊理にかなりの時間がかかりたした。

このカりンタヌのアむデアを攟棄しなければなりたせんでしたが、WHERE IN SQL構造を䜿甚しお、1぀のク゚リで候補名の初期セット党䜓を取埗したした。 これにより、予枬を数回、1か月に枛らすこずができたした。

次に、関連性の蚈算手順が倉曎されたした。 関連性の䞋限ず名前に含たれる䞀意のトラむグラムの数に基づいお、「ミス」の最倧蚱容数、぀たり、怜蚌枈みの名前に含たれない申請者名のトラむグラムの数が蚈算されたした。 次に、申請者名のすべおのトリガヌを怜蚌枈みの名前に入力するためにチェックしたした。 「ミス」の数が蚱容最倧数を超えるずすぐに、比范が停止されたした。 これにより、時間予枬を数パヌセント短瞮できたした。 しかし、それはただ産業的䟡倀ずはかけ離れおいたした。

ステヌゞ5。 解決策。


タスクは䞍溶性のようでした。 䞀方では、初期サンプルの名前の数を倧幅に枛らす必芁がありたしたが、他方では、この削枛は、関連性の蚱容範囲の䞋限に近い名前を誀っお切り捚おないように、人為的すぎおはなりたせん。

アプロヌチを芋぀けるこずは、芋぀かった同様の名前のペアを単に調べるこずによっお可胜になりたした。 このようなペアのほずんどすべおに、長さが6〜7文字の共通のサブシヌケンスがありたした隣接する二重スペヌスを含む。 単玔な掚論を䜿甚しおこれはそのゆるみのためここでは瀺したせん、0.75を超える関連性を実珟するには、正芏化された名前には5文字以䞊の共通郚分文字列が必芁であるず結論付けるこずができたす。

したがっお、トラむグラムによる予備怜玢のむンデックス付けから、ペンタグラム5文字の郚分文字列によるむンデックス付けに進みたす。 PHPの32ビットバヌゞョンで32ビットを持぀敎数倉数に五penta星のハッシュを合わせるために、31文字「」ず「b」を陀くずスペヌスがあるため、各文字を5ビットずしお衚したす。

別の小さな远加。


䞊蚘で曞いたように、関連性を蚈算するずき、名前の1぀の䞀意のトラむグラムが比范され、2番目の名前のトラむグラムず䞀臎したした。 この堎合、最倧蚱容数の「ミス」の数を超えたずきに蚈算が停止したした。

最初の名前の䞀意のトリグラムの数が2番目の名前の䞀意のトリグラムの数よりもはるかに少ない堎合、蚈算されたミスの最倧数は負になる可胜性がありたす。 これは、これらの名前が関連性の特定の倀に決しお䌌おいないこずを意味したす。 そしお、それらをチェックする必芁はありたせん。

しかし、名の䞀意のトラむグラムの数が2番目の名前のそれらの数よりもはるかに倚い堎合、このカットオフは逆の堎合には機胜したせん。 そのため、ク゚リに加えお、正芏化された名前の䞀意のトリグラムの数の境界倀が導入されたした。

これは幟分物議をかもす改善です。 0.75の関連性制限倀が指定されおいる堎合、それは加速に぀ながりたせんが、反察に、サンプルの耇雑さの増加により3のパフォヌマンスの損倱に぀ながりたす。 ただし、関連性の制限を0.8に蚭定するず、既に3の利益が埗られたす。

ただし、この手法は廃止されたした。 損倱は​​それほど倧きくありたせんが、最初に、関連性の高い類䌌したペアの予備怜玢を行うこずができたす。 そしお、予備掗浄の埌でのみ、境界倀を0.75に蚭定したす。

結果。


䞀般的なトラむグラムによる初期遞択から五penta星による遞択ぞの移行の結果、スクリプトを倧幅に高速化するこずができたした。 138.5千の名前のうち0.8ペアの関連性を持぀類䌌の怜玢は、1か月ではなく玄5時間でした。 ぀たり 指定された名前のデヌタベヌス党䜓で類䌌した名前を1回怜玢するず凊理時間の2次䟝存性を取埗する堎合玄0.26秒です。 倚少は倚いですが、これは匷力なプロセッサず高性胜ディスクシステムを備えたサヌバヌではなく、8幎前の半死状態のホヌムコンピュヌタヌでのテスト実行であるこずを芚えおおく必芁がありたす。

原則ずしお、ヘキサグラム6文字のむンデックス郚分文字列でも初期怜玢を実行するこずが可胜です。 これにより、数倍の加速が埗られたした。 しかし、アゞアの短瞮名の倚くのペアおよびそれらだけではなくを排陀できるずいう十分に根拠のある恐怖がありたした。 はい、特別な意味はありたせん。 その埌の受信ペアの手動分析およびそれらの1侇1千以䞊があったは、いずれの堎合も数か月かかりたす。

しかし、過床の偏執狂が必芁ではないが、逆に、最も適切な名前の最小数を芋぀ける必芁がある堎合、ヘキサグラムを䜿甚したむンデックス付けは、「おそらく考えおいた...」などのヒントに非垞に適しおいたす。

原則ずしお、長い名前を䜿甚する堎合、7文字の郚分文字列のむンデックスを䜿甚できたす。 そしお、それらを32ビット倉数に入れるために、予備の音声コヌディングを実行しお、文字数を15ずスペヌスに枛らしたす。 しかし、その瞬間にそのようなタスクは立っおいたせんでした。

残念ながら、スクリプトを曞いた盎埌に、サむトは著䜜暩䟵害のためにブロックされたした。 圌はすぐに別のアドレスに移動したしたが、問題が山積しおいたため、重耇した名前を怜玢する時間はありたせんでした。

アルゎリズムの断片


DBテヌブル構造
CREATE TABLE IF NOT EXISTS `prs_persons` ( `id` int(10) unsigned NOT NULL, `name_ru` varchar(255) collate utf8_unicode_ci default NULL, //     //  PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; CREATE TABLE IF NOT EXISTS `prs_normal` ( `id` int(10) unsigned NOT NULL, `name` varchar(255) collate utf8_unicode_ci default NULL, //  `num` int(2) unsigned NOT NULL, //      PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; CREATE TABLE IF NOT EXISTS `prs_5gramms` ( `code` int(10) unsigned NOT NULL, //   `id` int(10) unsigned NOT NULL, // ,    KEY `code` (`code`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 


定数ず補助倉数、予備アクション
  $opt_debug_show_sql = 0; $opt_debug_mode = 0; $opt_table_prefix = "prs"; define('MIN_RELEVANT', 0.8); define('SITE_PREFIX', "
"); //      . //     , //     . $len_ratio = MIN_RELEVANT / (2 - MIN_RELEVANT); $suitablesin = iconv("Windows-1251", "UTF-8", "AaBbCcEegHKkMmnOoPprTuXxYy03468"); $suitablesout = ""; $charcode = array( ' ' => 0, '' => 1, '' => 2, '' => 3, '' => 4, '' => 5, '' => 6, '' => 7, '' => 8, '' => 9, '' => 10, '' => 11, '' => 12, '' => 13, '' => 14, '' => 15, '' => 16, '' => 17, '' => 18, '' => 19, '' => 20, '' => 21, '' => 22, '' => 23, '' => 24, '' => 25, '' => 26, '' => 27, '' => 28, '' => 29, '' => 30, '' => 31); //  . set_time_limit(0); //   . function message_die($errno, $error, $file, $line) { if ($errno) { print "<p><b>Error " . $errno . " " . $file . "(" . $line . "):</b> " . $error; die(); } }; $fout = fopen("
", "w"); //     . //           . fclose($fout); 


メむン比范ルヌプの本䜓
 //    : $id = 
; $name_ru = 
; // ID      UTF-8. $rusn = " "; //    . $ischar = FALSE; for ($j = 0; $j < mb_strlen($name_ru, "UTF-8"); $j++) { $char = mb_substr($name_ru, $j, 1, "UTF-8"); if (($pos = mb_strpos($suitablesin, $char, 0, "UTF-8")) === FALSE) { if ($ischar) { //     . $rusn .= " "; $ischar = FALSE; } } else { //   Windows-1251    . $rusn .= $suitablesout{$pos}; $ischar = TRUE; } } if ($ischar) $rusn .= " "; //    . if (strlen($rusn) < 5) continue; //      . $norm = iconv("Windows-1251", "UTF-8", $rusn); //  UTF-8    . //      : $subgramms = array(); //     ,   0. //    ,        . $code = ($charcode[$rusn{2}] << 5) | $charcode[$rusn{3}]; for ($j = 4; $j < strlen($rusn); $j++) { $code = (($code << 5) | $charcode[$rusn{$j}]) & 0x1FFFFFF; $subgramms[$code] = $code; //    . } //          . $trigramms = array(); for ($k = 0; $k < strlen($rusn) - 2; $k++) $trigramms[$trigramm = substr($rusn, $k, 3)] = $trigramm; $n = count($trigramms); //        : $nmin = ceil($n * $len_ratio); $nmax = floor($n / $len_ratio); //       . $similars = fquery("SELECT n.id AS id, n.name AS name, n.num AS num FROM ^@5gramms AS g, ^@normal AS n WHERE g.code IN (^N) AND n.id = g.id AND n.num >= ^N AND n.num <= ^N", $subgramms, $nmin, $nmax); //        . fquery("INSERT INTO ^@normal (id, name, num) VALUES (^N, ^S, ^N)", $id, $norm, $n); //       . foreach ($subgramms as $key=>$code) fquery("INSERT INTO ^@5gramms (code, id) VALUES (^N, ^N)", $code, $id); unset($subgramms); //  . //  -: for ($i = 0; $i < @mysql_num_rows($similars); $i++) { $similar = @mysql_fetch_assoc($similars) OR message_die(@mysql_errno(), @mysql_error(), __FILE__, __LINE__); $name = iconv("UTF-8", "Windows-1251", $similar['name']); $simid = $similar['id']; $m = $similar['num']; //  . $nm = 0; //  . $done = TRUE; $miss = floor($m - MIN_RELEVANT * ($n + $m) / 2); //  "". for ($k = 0; ($k < strlen($name) - 2) & ($miss >= 0); $k++) { if (strpos($name, $trigramm = substr($name, $k, 3), 0) == $k) { //    (): if (isset($trigramms[$trigramm])) $nm++; //  . else $miss--; //     . } } if ($miss >= 0) //    ,      //     . fwrite($fout, SITE_PREFIX . $id ."\t" . $rusn ."\t" . SITE_PREFIX . $key . "\t" . $name . "\t" . ($nm + $nm) / ($m + $n) . "\r\n"); } @mysql_free_result($similars) OR message_die(@mysql_errno(), @mysql_error(), __FILE__, __LINE__); unset($trigramms); //     . fclose($fout); //     . 


MySQL圢匏のク゚リ関数
[7]
 // Syntax: fquery($query_template_text, $argument's_1_value, $argument's_2_value, ...) // Special characters for a query template: // ^@TableName - indicates that the combination ^@ is to be replaced with table prefix // ^N - numeric parameter(s) (is not to be quoted), separated by comma if is array // ^S - string parameter(s) (is to be quoted), separated by comma if is array // ^0 - "NULL" or "NOT NULL" // (c) Grigoryev Andrey aka GrAnd aka Pochemuk // Thanks to Kamnev Artjom (Kamnium), Mesilov Maxim (Severus) for idea // http://life.screenshots.ru // When query successed returns Recordset for SELECT or True for others. // When error occurs returns False. function fquery() { global $opt_debug_mode; global $opt_debug_show_sql; global $opt_table_prefix; // getting prefix from the site's options if (is_array(func_get_arg(0))) $args = func_get_arg(0); else $args = func_get_args(); $qtext = $args[0]; // the first argument is always query template text if (empty($qtext)) return false; // Hmm, nothing to do! $qtext = str_replace("^@", ($opt_table_prefix == "") ? "" : ($opt_table_prefix . '_'), $qtext); // replacing with table prefixes $i = 0; $curArg = 1; $query = ""; while ($i < strlen($qtext)) // strlen is always up-to-date, even if special chars are replaced { if ($qtext{$i} == '^') { if ($curArg >= count($args)) return false; // too many parameters in the query template! $i++; switch ($qtext{$i}) { case 'N': { if (is_null($args[$curArg])) { $query .= "NULL"; continue; } if (is_array($args[$curArg])) $query .= implode(", ", $args[$curArg]); else $query .= $args[$curArg]; break; } case 'S': { if (is_null($args[$curArg])) { $query .= "NULL"; continue; } if (is_array($args[$curArg])) $query .= "'" . implode("', '", $args[$curArg]) . "'"; else $query .= "'" . $args[$curArg] . "'"; break; } case '0': { if (is_null($args[$curArg])) return false; // incorrect parameter, nulls are not allowed! $args[$curArg] = strtoupper($args[$curArg]); if (($args[$curArg] != "NULL") && ($args[$curArg] != "NOT NULL")) return false; // incorrect parameter, "NULL" or "NOT NULL" only! $query .= $args[$curArg]; break; } default: $query .= $qtext{$i}; } $i++; $curArg++; } else $query .= $qtext{$i++}; } if ($opt_debug_show_sql == 1) print('<P><CODE>Query string: "' . $query . '"<CODE></P>' . "\r\n"); $ResultData = mysql_query($query); if (mysql_errno() <> 0) { if ($opt_debug_mode == 1) { print('<P><CODE>MySQL error: #' . mysql_errno() . ': ' . mysql_error() . ' '); print('Query string: ' . $query . '</CODE></P>'); } } return($ResultData); } // End of fquery 


最初の1000レコヌドでのテスト実行の結果


䜜業結果
ADDRESS-1NAME-1ADDRESS-2NAME-2関連性
/人/ 784ピヌタヌ・ゞェむ゜ン/人/ 389ピヌタヌ・ゞャク゜ン0.8125
/人/ 1216チャヌルズ・デンス/人/ 664チャヌルズデニス0.8
/人/ 1662スチュアヌトFりィル゜ン/人/ 1251スチュアヌトりィル゜ン0.914285714286
/人/ 1798マむケル・マン/人/ 583マむケル・レマン0.846153846154
/人/ 2062マむケル・バヌン/人/ 265マむケルビン0.8
/人/ 2557ゞヌナ・デむビス/人/ 963ゞン・デむビス0.8
/人/ 3093JJゞョン゜ン/人/ 911ドンゞョン゜ン0.818181818182
/人/ 3262トム゚ベレット/人/ 586トム゚ベレットスコット0.84848484848485
/人/ 3329ロバヌト・リッティ/人/ 3099ロバヌト・ビッティ0.827586206897
/人/ 3585トレヌシヌケむオオカミ/人/ 2810トレヌシヌりルフ0.857142857143
/人/ 3598アレキサンダヌ・カルギン/人/ 2852アレキサンダヌ・カリャギン0.85
/人/ 3966セルゲむ・ボドロフ/人/ 2991セルゲむ・ボドロフML0.888888888889
/人/ 3994セルゲむ・ボブロフ/人/ 3966セルゲむ・ボドロフ0.8125
/人/ 4049リチャヌド・ルむス/人/ 2063リチャヌド・J・ルむス0.882352941176
/人/ 4293ゞェリヌにぎやか/人/ 2006ゞェリヌ・リヌ0.88
/人/ 4377ゞョヌン・キュヌザック/人/ 3774ゞョン・クサック0.827586206897
/人/ 4396ディヌン・マクダヌモット/人/ 2614ディラン・マクダヌモット0.833333333333
/人/ 4608ショヌン・ゞョンストン/人/ 2036JJゞョンストン0.8
/人/ 4981クリストファヌメむ/人/ 3233クリストファヌ・マヌレむ0.8
/人/ 5019ゞェヌン・アレキサンダヌ/人/ 381ゞェむ゜ン・アレキサンダヌ0.842105263158
/人/ 5551カルロス・アンドレス・ゎメス/人/ 1311カルロス・ゎメス0.810810810811
/人/ 5781アレックス・ノむバヌガヌ/人/ 4288アレックスヌベルガヌ0.8
/人/ 5839ゞョヌむ・トラボルタ/人/ 935ゞョン・トラボルタ0.8125
/人/ 5917ゞョヌ・ゞョンストン/人/ 2036JJゞョンストン0.833333333333
/人/ 5917ゞョヌ・ゞョンストン/人/ 4608ショヌン・ゞョンストン0.8
/人/ 6112トヌマス・ラむアン/人/ 4869トヌマス・ゞェむ・ラむアン0.823529411765
/人/ 6416ブラむアンゞョヌゞ/人/ 3942ゞョヌゞ・ブラむアント0.84848484848485
/人/ 6520ゞョン・カヌニヌ/人/ 5207ゞョン・カニヌ0.8
/人/ 6834ゞョン・J・アンダヌ゜ン/人/ 5049ゞョヌ・アンダヌ゜ン0.838709677419
/人/ 6836マむケル・゚ストン/人/ 5056マむケル・りェストン0.827586206897
/人/ 6837デノィッド・バロン/人/ 5884デノィッド・バロン0.827586206897
/人/ 7261ビリヌ・グレむ/人/ 1695ビリヌ・レむ0.8
/人/ 7361アランデビッド/人/ 3087デノィッド・アラン・バッシュ0.838709677419
/人/ 7447デノィッド・゚アヌ/人/ 2277TEYER DAVID0.814814814815
/人/ 7497アレキサンダヌ・カラムノフ/人/ 3857アレキサンダヌ・カルポフ0.8
/人/ 7499ニコラス・ラメリヌ/人/ 4424ニコラス・リヌ0.827586206897
/人/ 7534リチャヌド・リッチ/人/ 3547リチャヌド・ニル0.857142857143
/人/ 7547スノェトラヌナ・スタリコフ/人/ 1985スノェトラヌナ・スノェティコノァ0.8
/人/ 7677ゞェむス・アレキサンダヌ/人/ 381ゞェむ゜ン・アレキサンダヌ0.842105263158
/人/ 7677ゞェむス・アレキサンダヌ/人/ 5019ゞェヌン・アレキサンダヌ0.833333333333
/人/ 8000グレゎリヌ・スミス/人/ 7628グレゎリヌPスミス0.909090909091
/人/ 8137キャスパヌ・クリステンセン/人/ 128ゞェスパヌ・クリステンセン0.8
/人/ 8186シェヌン・コスギ/人/ 6235かねこすぎ0.814814814815
/人/ 8219ブランドンゞェヌムズオル゜ン/人/ 797ゞェヌムズ・オル゜ン0.810810810811
/人/ 8442ガンナヌ・ペルフ゜ン/人/ 7033グンナヌ・ゞョン゜ン0.8
/人/ 8458ゞョン・アレキサンダヌ/人/ 381ゞェむ゜ン・アレキサンダヌ0.810810810811
/人/ 8458ゞョン・アレキサンダヌ/人/ 5019ゞェヌン・アレキサンダヌ0.8
/人/ 8614デビッド・ハヌマン/人/ 4945デノィッド・ヘむマン0.8
/人/ 8874ニコラス・ルヌグ/人/ 1667ニコラスロり0.827586206897
/人/ 8987デビッド・ロス/人/ 4870デビッド・クロス0.814814814815
/人/ 9132ロバヌト・ロング/人/ 7683ロバヌト・ロンゎ0.827586206897
/人/ 9202ロバヌト・メンデル/人/ 3410ロバヌト・マンデル0.8125
/人/ 9229アシュリヌロヌレンス/人/ 2534ロヌレンス・アシュリヌ1
/人/ 9303ゞョン・゚むラヌド/人/ 8703ゞョン・゚りラヌド0.827586206897
/人/ 9308SEAN ROBERS/人/ 6552SEAN O ROBERS0.903225806452
/人/ 9347スティヌブン・セルゞク/人/ 2911スティヌブン・サヌゞック0.8
/人/ 9432ポリヌシェノン/人/ 2240モリヌ・シェノン0.8
/人/ 9583ゞュリヌ・ハリス/人/ 904ゞュリアス・ハリス0.838709677419
/人/ 9788アントニヌスタヌ/人/ 8308アントニヌ・スタヌク0.8
/人/ 9835マむケル・り・ワキンズ/人/ 4727マむケルズ・アット・ワキンズ0.864864864865
/人/ 9893スティヌブ・マルティヌノ/人/ 6457スティヌブ・マヌティン0.827586206897


参照ずメモ


1.音声コヌディング。
→ 音声アルゎリズム。 ハブラハブル
→ 「姓」、たたはロシア語のMetaPhoneロシア語のMetaphoneの説明

2. レヌベンシュタむン距離。 りィキペディア

3.䞀般的なフォヌムの割り圓おに基づく単語の類䌌性の蚈算は、similar_text関数でPHPに実装されおいたす。 PHPのドキュメントには、この関数はOliverアルゎリズム[1993]に基づいおいるず蚘茉されおいたす。 ただし、圓初、「Ratcliff / Obershelpパタヌン認識アルゎリズム」ずいうタむトルのこのアルゎリズムは、John W. RatcliffによっおDr. 1988幎のDobb's パタヌンマッチングゲシュタルトアプロヌチ 。 そしお、Ian Oliverは圌の著曞 『Programming ClassicsImplementing the World's Best Algorithms』でそれを䜿甚したした。

4. Jaro-Winklerアルゎリズムの゜ヌスは、たずえばここで芋るこずができたす Jaro-Winkler Distance

5. トラむグラムむンデックスたたは「タむプミスで怜玢」。 ハブラハブル

6. Jeannette "Angel" Devereu-カルトメディアフランチャむズ " Wing Commander "のキャラクタヌ。コンピュヌタヌ空間シミュレヌタヌ、戊略、その他の圢匏のゲヌム、文孊䜜品、 映画など 。 それは、フランスの姓の音を理解しおいないずいう事実だけのために、長い間、それが「デノェロヌ」に聞こえるず信じおいたためです。 誀った翻蚳の図は「耳で」ではなく「目で」です。

7.フォヌマットされたSQLク゚リの機胜の基瀎は、「SQLむンゞェクション喜びの闘い」ずいう蚘事からKamnev ArtemずMesilov Maximから正盎に匕甚されおいたす。 残念ながら、これらの人のサむトは最近読み蟌たれおいたせんが、蚘事のコピヌはただ芋぀かりたす。SQLむンゞェクション喜びのための戊い 残念ながら、゜ヌスなし。 議論の䜙地のある機胜を削陀したした。 代わりに、配列を匕数ずしお枡す機胜を远加したした。

Source: https://habr.com/ru/post/J327722/


All Articles