6

大量 (~数千) の文字列を保存し、ワイルドカードを使用して一致を実行できるようにしたい。

たとえば、サンプル コンテンツは次のとおりです。

  • Folder1
  • Folder1/Folder2
  • Folder1/*
  • Folder1/Folder2/Folder3
  • Folder2/Folder*
  • */Folder4
  • */Fo*4

(各行にはタグなどの追加データもありますが、一致はそのキーに対してのみ行われます)

データと照合したいものの例を次に示します。

  • Folder1
  • Folder1/Folder2/Folder3
  • Folder3

(*ここではワイルドカードなので、別の文字にすることもできます)

%MySQL テーブルに保存し、演算子でワイルドカードを使用することを素朴に検討しましたLIKEが、MySQL インデックスはワイルドカードの左側の文字に対してのみ機能し、私の場合はどこでもかまいません (つまり%/Folder3)。

だから私はPHPから使用できる高速なソリューションを探しています。そして私はオープンです:それは別のサーバー、正規表現を含むファイルを使用するPHPライブラリ、...

4

9 に答える 9

1

MySQL の正規表現エンジンの使用を検討しましたか? 次のようなことを試してください:

SELECT * FROM your_table WHERE your_query_string REGEXP pattern_column

これにより、クエリ文字列が一致する正規表現キーを持つ行が返されます。クエリを実行してすべてのデータを取得し、PHP で照合を行うよりも優れたパフォーマンスが得られると思います。

詳細はこちら: http://dev.mysql.com/doc/refman/5.1/en/regexp.html

于 2013-03-14T04:49:17.170 に答える
0

マルチコアアプローチを使用して、その検索をほんのわずかな時間で解決することをお勧めします。FPGAを使用して検索と照合を行うことをお勧めしますが、おそらくそれを行うのが最も難しい方法です。CUDAを使用してこの記事を検討してください。その検索を行うことができます。通常の16倍の時間で、マルチコアCPUシステムでは、posixまたはコンピューターのクラスター(MPIなど)を使用してジョブを実行できます。Gearmanサービスを呼び出して、高度なアルゴリズムを使用して検索を実行できます。

于 2013-02-26T01:20:03.903 に答える
0

ワイルドカード(*)はデータに含まれ、クエリには含まれないため、データを細かく分割することから始める必要があると思います。次のような列を持つインデックステーブルを作成する必要があります。

dataGroup INT(11),
exactString varchar(100),
wildcardEnd varchar(100),
wildcardStart varchar(100),

「Folder1/Folder2」のような値がある場合は、それを「exactString」に格納し、メインデータテーブルの値のIDを上記のインデックステーブルの「dataGroup」に割り当てます。

「Folder1/*」のような値がある場合は、「Folder1 /」の値を「wildcardEnd」に保存し、メインテーブルの値のIDを上記の表の「dataGroup」フィールドに再度割り当てます。

次に、以下を使用してクエリ内で照合を行うことができます。

indexTable.wildcardEnd = LEFT('Folder1/WhatAmILookingFor/Data', LENGTH(indexTable.wildcardEnd))

これにより、検索文字列('Folder1 / WhatAmILookingFor / Data')が "Folder1 /"に切り捨てられ、wildcardEndフィールドと照合されます。mysqlは、すべての行を切り捨てるのではなく、最初の文字から始めて、すべての行と照合する(Bツリーインデックスを使用)のに十分賢いと思います。

「*/Folder4」のような値は「wildcardStart」フィールドに入りますが、逆になります。ミッシーエリオットを引用するには:「それは価値があります、私はそれを働かせてください私は私のものを置き、それを裏返し、そしてそれを逆にします」(http://www.youtube.com/watch?v=Ke1MoSkanS4)。したがって、「wildcardStart」に「4redloF/」の値を格納します。次に、次のようなWHEREが行に一致します。

indexTable.wildcardStart = LEFT(REVERSE('Folder1/WhatAmILookingFor/Folder4'), LENGTH(indexTable.wildcardStart))

もちろん、アプリケーションロジックですでに「REVERSE」を実行することもできます。

ここで、注意が必要な部分について説明します。「*/Fo * 4」のようなものは、2つのレコードに分割する必要があります。

# Record 1
dataGroup ==> id of "*/Fo*4" in data table
wildcardStart ==> oF/
wildcardEnd ==> /Fo

# Record 2
dataGroup ==> id of "*/Fo*4" in data table
wildcardStart ==> 4

ここで、何かを一致させる場合は、dataGroupのすべてのインデックスレコードが完全に一致するように返され、重複が発生しないように注意する必要があります。これはSQLでも解決できる可能性がありますが、この質問を超えています。

于 2013-02-28T10:40:27.477 に答える
0

私の場合、キーフィールドを2回保存します... 1回は順方向、もう1回は逆方向です(mysqlの逆関数を参照)。次に、left(main_field)とleft(reversed_field)を使用してインデックスを検索できます。文字列の途中と先頭(「* Folder1 * Folder2」など)にワイルドカードがある場合は役に立ちませんが、先頭または末尾にワイルドカードがある場合は役立ちます。

たとえば、* / Folder1を検索する場合は、left(reverse_field、8)='1redloF/';を検索します。Folder1 / * / FolderX検索の場合、left(reverse_field、8)='XredloF /'およびleft(main_field、8)='Folder1 /'

于 2013-02-26T01:26:59.727 に答える
0

キーとそれに関連付けられたペイロードを、キーの英数字順に並べられたバイナリ ツリー表現に読み取ることをお勧めします。キーがひどく「まとまっていない」場合は、バランスの取れたツリーの (わずかな追加の) オーバーヘッド構築を回避できます。問題を正しく理解していれば、データは頻繁に変更され、ノードを追加/削除/更新するのではなく、ツリーを再構築するのが最も簡単なため、ツリーのメンテナンスコードを回避することもできます。ツリーへの読み込みのオーバーヘッドは、最初の並べ替えを実行するのと同様であり、値を検索するためのツリー トラバーサルは単純で、一連の文字列に対して正規表現を実行するよりもはるかに効率的です。作業中に、ツリー内のワイルド カードが検索スペースを切り詰めるショートカットにつながることに気付くかもしれません。

于 2013-03-04T20:07:57.627 に答える
0

データベースは、この種の検索を行うための適切なツールではありません。データベース (任意のデータベースおよび任意の構造) を使用して文字列を格納できますが、すべての検索をメモリ内で実行するコードを記述する必要があります。データベースからすべての文字列をロードし (数千の文字列は実際には大したことではありません)、それらをキャッシュして、それらに対して search\match アルゴリズムを実行します。

標準ツールは達成しようとしているものに対してやり過ぎであり、必要なものを正確に達成できるという保証はないため、おそらくアルゴリズムを自分でコーディングする必要があります。

ワイルドカード ベースの文字列の正規表現を作成し、入力に対してそれらの正規表現を実行します。おそらく、正規表現が正しくなるまで何らかの作業を行う必要がありますが、それが最速の方法です。

于 2013-03-02T17:13:58.813 に答える
0

文字列がある種の階層構造を表している場合 (サンプル コンテンツのように見えます)、実際には「実際の」ファイルではありませんが、代替ソリューションを受け入れていると言っています。ファイルベースのインデックスのようなものを検討してみませんか?

  • 次のような新しいディレクトリを選択しますmyindex
  • 文字列キーを場所とファイル名として使用して、エントリごとに空のファイルを作成しますmyindex

を使用して一致を見つけることができるようglobになりました - 階層的なファイル構造のおかげで、グロブ検索はすべてのデータベース エントリを検索するよりもはるかに高速です。必要に応じて、結果を MySQL データと一致させることができます。キーの MySQL インデックスのおかげで、このアクションは非常に高速になります。

ただし、 、またはMySQL データベースのmyindex構造を更新することを忘れないでください。INSERTUPDATEDELETE

このソリューションは、幅の広い階層構造よりもかなり深い階層構造を持つ巨大なデータセット (ただし、@Kyle が言及したほど巨大ではない) でのみ競合します。

編集 申し訳ありませんが、ワイルドカードが保存された文字列自体ではなく、検索語に含まれている場合にのみ機能します。

于 2013-02-27T15:38:30.977 に答える
-1

実行SELECT folder_col, count(*) FROM your_sample_table group by folder_colすると、folder_colの値が重複しますか(つまり、count(*)が1より大きい)?

そうでない場合は、有効なスフィンクスインデックスを生成するSQLを生成できることを意味します(http://sphinxsearch.com/を参照)。

于 2013-02-22T15:03:45.680 に答える
-1

MySQL の大規模なデータ コレクションに対してテキスト検索を行うことはお勧めしません。データを保存するにはデータベースが必要ですが、それだけです。検索には、次のような検索エンジンを使用します。

これらのサービスを使用すると、あらゆる種類のファンキーなテキスト検索 (ワイルドカードを含む) を瞬く間に行うことができます ;-)

于 2013-02-27T18:03:23.187 に答える