2

特定の文字列に対して php を使用して配列 (またはさらに良いのは、mysql テーブルの列) を検索できるようにしたいと考えています。ただし、私の目標は、検索した文字列と一致する文字の数を (正しい順序で) 返すこと、または検索結果がどれほど合理的かを確認する他の方法を返すことです。デフォルトで上位の結果を表示するか、上位のいくつかのユーザーオプションを提供したい. 私は次のようなことができることを知っています

$citysearch = mysql_query("  SELECT city FROM $table WHERE city LIKE '$city' ");

しかし、それがどれほど正確かを判断する方法がわかりません。

目標は次のようになります:
a) 検索語が「milwakee」またはそれに類似したものである場合、「Milwaukee」を検索します。
b) 検索語が「west」の場合、「West Bend」や「Westmont」などを返します。

これを行う良い方法を知っている人はいますか?

4

4 に答える 4

3

MySQL での全文検索を確認する必要があります。また、Apache Lucene プロジェクトの Zend のポートであるZend_Search_Luceneも確認してください。

于 2009-01-13T05:42:38.227 に答える
2

さらに検索すると、レーベンシュタイン距離にたどり着き、次に similar_text にたどり着きました。

similar_text("input string", "match against this", $pct_accuracy);

文字列を比較し、精度を変数として保存します。レーベンシュタイン距離は、1 つの文字列から別の文字列に移動するために実行する必要がある、1 つの文字に対する削除、挿入、または置換関数の数を決定し、各関数の重み付けを異なる方法で許容します (たとえば、置換のコストを高くすることができます)。文字を削除するよりも文字)。これは明らかに高速ですが、similar_text よりも正確ではありません。私が他の場所で読んだ他の投稿では、10000 文字未満の文字列の場合、速度に機能上の違いはないと述べています。

私はそれを機能させるために見つけたものの修正版を使用することになりました。これにより、上位 3 つの結果が保存されます (完全一致の場合を除く)。

$input = $_POST["searchcity"];
$accuracy = 0;
$runner1acc = 0;
$runner2acc = 0;
while ($cityarr = mysql_fetch_row($allcities)) {
  $cityname = $cityarr[1];
  $cityid = $cityarr[0];
  $city = strtolower($cityname);
  $diff = similar_text($input, $city, $tempacc);

  // check for an exact match
  if ($tempacc == '100') {

    // closest word is this one (exact match)
    $closest = $cityname;
    $closestid = $cityid;
    $accuracy = 100;

    break;
  }

  if ($tempacc >= $accuracy) { // more accurate than current leader
    $runner2 = $runner1;
    $runner2id = $runner1id;
    $runner2acc = $runner1acc;
    $runner1 = $closest;
    $runner1id = $closestid;
    $runner1acc = $accuracy;
    $closest  = $cityname;
    $closestid = $cityid;
    $accuracy = $tempacc;
  }
  if (($tempacc < $accuracy)&&($tempacc >= $runner1acc)) { // new 2nd place
    $runner2 = $runner1;
    $runner2id = $runner1id;
    $runner2acc = $runner1acc;
    $runner1 = $cityname;
    $runner1id = $cityid;
    $runner1acc = $tempacc;
  }
  if (($tempacc < $runner1acc)&&($tempacc >= $runner2acc)) { // new 3rd place
    $runner2 = $cityname;
    $runner2id = $cityid;
    $runner2acc = $tempacc;
  }
}

echo "Input word: $input\n<BR>";
if ($accuracy == 100) {
  echo "Exact match found: $closestid $closest\n";
} elseif ($accuracy > 70) { // for high accuracies, assumes that it's correct
  echo "We think you meant $closestid $closest ($accuracy)\n";
} else {
  echo "Did you mean:<BR>";
  echo "$closestid $closest? ($accuracy)<BR>\n";
  echo "$runner1id $runner1 ($runner1acc)<BR>\n";
  echo "$runner2id $runner2 ($runner2acc)<BR>\n";
}
于 2009-01-15T22:41:29.227 に答える
0

これは非常に複雑になる可能性があり、存在することは確かですが、私は個人的に優れたサードパーティのライブラリを認識していません。ただし、他の人はいくつかの定型的な解決策を提案できるかもしれません.

私は過去に何度かゼロから似たようなことを書きました。そのルートをたどると、すべてのクエリですべてのレコードを取得し、それらに対して計算を実行する必要があるため、PHP だけで実行したいとは思わないでしょう。ほぼ確実に、仕様を満たす一連のインデックス テーブルを作成する必要があります。

たとえば、「Milwaukee」が最終的に「milwakee」と綴られる可能性があると想像する方法について、ルールを考え出す必要があります。これに対する私の解決策は、母音圧縮と重複圧縮を行うことでした (これらが実際に検索用語であるかどうかはわかりません)。したがって、ミルウォーキーは次のようにインデックス付けされます。

  • ミルウォーキー
  • m_lw__k__
  • m_lw_k_

「milwaukee」の検索クエリが入ってきたら、テキスト入力に対して同じプロセスを実行してから、インデックス テーブルで次の検索を実行します。

SELECT cityId,
       COUNT(*)
  FROM myCityIndexTable
 WHERE term IN ('milwaukee', 'm_lw__k__', 'm_lw_k_')

"milwakee" の検索クエリが入ってきたら、テキスト入力に対して同じプロセスを実行し、インデックス テーブルで次の検索を実行します。

SELECT cityId,
       COUNT(*)
  FROM myCityIndexTable
 WHERE term IN ('milwaukee', 'm_lw_k__', 'm_lw_k_')

Milwaukee (スペルが正しい) の場合、カウントとして "3" が返されます。

Milwakee (スペルが間違っている) の場合、カウントとして "2" が返されます (m_lw__k__中央に母音が 1 つしかなく、パターンに一致しないため)。

カウントに基づいて結果を並べ替えると、「Milwaukee」が「Milwakee」よりも上位に並べ替えられるというルールの 1 つを満たすことになります。

このシステムを一般的な方法で構築したい場合 ($tableクエリで を使用することで示唆されているように)、用語を適切なテーブルにマップするために別のマッピング テーブルが必要になる可能性があります。

これが最善の(または良い)方法であると示唆しているわけではありません.サードパーティのソリューションなしでこれを試してみる場合に役立つかもしれない過去に私が行ったことです.

于 2009-01-13T05:38:28.560 に答える
0

LIKE の最も厄介な結果は、この "%man" です。これにより、ファイル内のすべての女性が返されます。上場の場合、おそらくそれほど悪くない解決策は、検索の針を短くし続けることです。あなたの場合、検索 $ が「milwa」と同じくらい短い場合に一致が表示されます。

于 2010-01-23T02:04:18.770 に答える