2012-03-27 12 views
6

私は同様の質問を数ヶ月前に尋ねました。ここにあります:MySQL Query based on stringMySQLの文字列の比較

私が遭遇している問題は、これは特定の順序でしか動作せず、場合によってはうまくいきます。ここで

は(重複が、実際のデータを意図している)このクエリがフィルタリングされたデータの抜粋です:

が私の最後の質問( MySQL Query based on string)に役立った1つのクエリが1つのインスタンスのよく働い
- BELLMORE 
- ATLANTIC BCH 
- ATLANTIC BEACH 
- E HILLS 
- EAST HILLS 
- EAST ROCKAWAY 
- FAR ROCKAWAY 
- FLORAL PARK 
- FLORAL PARK 
- HIGHLAND HEIGHTS 
- N HIGHLAND HGTS 
- NORTH HIGHLAND HEIGHTS 

他のインスタンスでは失敗しました。

select names from tablename group by substring_index(names," ",1) 

返します:ここにクエリがある

- BELLMORE 
- ATLANTIC BEACH 
- EAST HILLS 
- FAR ROCKAWAY 
- FLORAL PARK 
- HIGHLAND HEIGHTS 
- N HIGHLAND HGTS 
- NORTH HIGHLAND HEIGHTS 

1つの問題は、あなたが見ることができるように、それが唯一の最初の単語を使用していたので、それは持つべきではないという街を除去したことですそれをグループ化する削除したものは次のとおりです。

これはGROUPされました。

私はこれを続けて書いているので、静的な都市名と可変部分の位置が常に変化しているので、ほとんど不可能だと感じています。特定の文字数を比較できない限り。それは遠くに完璧ではない。誰かが何らかの洞察力を持っていると思ったり、そうしたことをして遂行したりしたと思ったら、私はフィードバックと指針を感謝します。終了結果は次のようになります。

- BELLMORE 
- ATLANTIC BEACH 
- EAST HILLS 
- EAST ROCKAWAY 
- FAR ROCKAWAY 
- FLORAL PARK 
- HIGHLAND HEIGHTS 
+1

「N」=「北」、「Hghts」=「普通」などの共通の同義語のリストを手動で生成できますか? Heights'など – mellamokb

答えて

2

私の提案は、高価なクエリになりますが、それはすべての時間を必要とされないようにうまくいけば、あなたのデータの臨時の「クリーニング」を実行する操作のこのタイプを使用することができますこのデータを照会します。

Levenshtein distanceの式を調べることをお勧めします。これは、2つのシーケンスの差の量を測定するための文字列メトリックです。

テーブルのデカルト積の距離を計算する必要がないようにするには、最初に同じ文字で始まるような、より迅速な健全性チェックと比較する都市と住所のセットを絞り込むことができます同様の長さを有する。

最初に、あなたはその後、唯一の非常に小さなレーベンシュタイン距離のレコードを返すことによってオフに開始することができます...あなたはその後、試合の一つのバリエーションを選択することができ、あなたのデータを正規化するために、他のレコードに適用するために戻りました。

その後、偽陽性が多すぎるようになるまで、徐々に距離を広げることができます。

Here's an implementation directly in MySql

CREATE FUNCTION levenshtein(s1 VARCHAR(255), s2 VARCHAR(255)) 
    RETURNS INT 
    DETERMINISTIC 
    BEGIN 
    DECLARE s1_len, s2_len, i, j, c, c_temp, cost INT; 
    DECLARE s1_char CHAR; 
    -- max strlen=255 
    DECLARE cv0, cv1 VARBINARY(256); 
    SET s1_len = CHAR_LENGTH(s1), s2_len = CHAR_LENGTH(s2), cv1 = 0x00, j = 1, i = 1, c = 0; 
    IF s1 = s2 THEN 
     RETURN 0; 
    ELSEIF s1_len = 0 THEN 
     RETURN s2_len; 
    ELSEIF s2_len = 0 THEN 
     RETURN s1_len; 
    ELSE 
     WHILE j <= s2_len DO 
     SET cv1 = CONCAT(cv1, UNHEX(HEX(j))), j = j + 1; 
     END WHILE; 
     WHILE i <= s1_len DO 
     SET s1_char = SUBSTRING(s1, i, 1), c = i, cv0 = UNHEX(HEX(i)), j = 1; 
     WHILE j <= s2_len DO 
      SET c = c + 1; 
      IF s1_char = SUBSTRING(s2, j, 1) THEN 
      SET cost = 0; ELSE SET cost = 1; 
      END IF; 
      SET c_temp = CONV(HEX(SUBSTRING(cv1, j, 1)), 16, 10) + cost; 
      IF c > c_temp THEN SET c = c_temp; END IF; 
      SET c_temp = CONV(HEX(SUBSTRING(cv1, j+1, 1)), 16, 10) + 1; 
      IF c > c_temp THEN 
       SET c = c_temp; 
      END IF; 
      SET cv0 = CONCAT(cv0, UNHEX(HEX(c))), j = j + 1; 
     END WHILE; 
     SET cv1 = cv0, i = i + 1; 
     END WHILE; 
    END IF; 
    RETURN c; 
    END; 
+0

これはどのように動作するのかわかりません。 「N HIGHLAND HGTS」と「NORTH HIGHLIGHTS HEIGHTS」の距離を7とし、「EAST ROCKAWAY」と「FAR ROCKAWAY」の距離はわずか4になるのではないでしょうか?選択した任意の距離に対する偽陽性/偽陰性の数。 – mellamokb

+0

@mellamokbあなたは絶対に正しいです...彼のサンプルデータをより詳細に見ると、あなたの提案したような共通の同義語のセットと組み合わせて使用​​すれば実現可能です。 –

1

Toughie ...私は確かにマイケルの提案を活用して、その中のデータベースにユニークな地名を維持する可能性を投げると思います

これにより、新しい場所の追加時に文字列距離計算しか使用できなくなります。次に、levenshteinが識別する場所にassociate_idを割り当てることで、場所を管理できます。

おそらく、ジオロケーションなどの他のデータを使用して、場所を関連付ける方法をさらに調整することができます。あなたの問題に最も適した解決策ではないかもしれません...