2012-03-27 3 views
6

Я задал аналогичный вопрос пару месяцев назад. Находится здесь: MySQL Query based on stringСравнение строк MySQL

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

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

- 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 based on string) работал хорошо для одного экземпляра и не удалось выполнить другой экземпляр. Вот запрос:

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 

Это было GROUP'ed BY EAST.

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

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

Можете ли вы вручную создать список общих синонимов, таких как 'N' =' North', 'Hghts' =' Heights' и т. Д. – mellamokb

ответ

2

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

Вы можете рассмотреть формулу Levenshtein distance ... которая является строковой метрикой для измерения величины разницы между двумя последовательностями.

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

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

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

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 HIGHLAND HEIGHTS» равным 7, а расстояние «EAST ROCKAWAY» и «FAR ROCKAWAY» было бы всего 4. Кажется, будет очень большой количество ложных срабатываний/ложных негативов для любого выбранного расстояния. – mellamokb

+0

@mellamokb Вы абсолютно правы ... более внимательно изучите его образцы данных, это было бы возможно только при использовании в сочетании с набором общих синонимов, как вы предлагали. –

1

орешек ...

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

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

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

Смежные вопросы