Сравнение строк MySQL - PullRequest
       6

Сравнение строк MySQL

6 голосов
/ 28 марта 2012

Я задал похожий вопрос пару месяцев назад. Расположен здесь: MySQL Query на основе строки

Проблема, с которой я сталкиваюсь, заключается в том, что это работает только в одном конкретном порядке, а в некоторых случаях работает слишком хорошо.

Вот фрагмент данных, которые фильтрует этот запрос (предполагаются дубликаты, фактические данные):

- 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

Один запрос, который помог в моем последнем вопросе ( MySQL Query на основе строки ), работал хорошо для одного экземпляра и не удался для другого экземпляра. Вот запрос:

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

Проблема с этим в том, что, как вы видите, он удалил город, которого у него не должно быть, потому что он использовал только первое слово для группировки его. Тот, который он удалил, был:

- EAST ROCKAWAY

Это было ГРУППА НА ВОСТОКЕ.

Продолжая писать это, я чувствую, что это практически невозможно, потому что положение статического названия города относительно переменных частей всегда меняется. Если вы не можете сравнить определенное количество символов. Что далеко не безупречно. Если кто-то думает, что у него есть какое-то понимание, или он работал и достиг такого уровня, я буду признателен за отзывы и рекомендации. Конечный результат будет:

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

Ответы [ 2 ]

2 голосов
/ 28 марта 2012

Мое предложение будет дорогим запросом, но, надеюсь, вы могли бы использовать этот тип операции для периодической «очистки» ваших данных, чтобы не требовалось каждый раз, когда вы запрашиваете эти данные.

Вы можете рассмотреть поиск формулы расстояния Левенштейна ... которая представляет собой строковую метрику для измерения величины разности между двумя последовательностями.

Чтобы избежать необходимости вычислять расстояние для декартового произведения вашей таблицы, вы можете сначала сузить набор городов и адресов для сравнения с более быстрой проверкой вменяемости ... например, они начинаются с одной и той же буквы, иимеют аналогичную длину.

Первоначально вы могли бы затем начать с возвращения только записей с очень маленьким расстоянием Левенштейна ... Затем можно выбрать один вариантвозвращенные совпадения применяются к другим записям для нормализации ваших данных.

Затем можно постепенно увеличить расстояниедо тех пор, пока вы не начнете получать слишком много ложных срабатываний.

Вот реализация непосредственно в 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;
1 голос
/ 28 марта 2012

Toughie ...

Я, конечно, воспользуюсь предложением Майкла и добавлю к этому возможность сохранения уникальных географических названий в базе данных.

Это позволит вам использовать толькорасчет расстояния строки при добавлении новых мест.Затем вы можете управлять местами, назначая associate_id тем местам, которые идентифицирует Левенштейн.

Возможно, вы могли бы использовать некоторые другие данные (например, геолокацию) для дальнейшей настройки того, как вы связываете места.Возможно, использование только топонима - не лучшее решение вашей проблемы ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...