2012-04-28 6 views
3

저는 Metaphone과 Double Metaphone 검색 알고리즘에 대해 배우기 시작했습니다. 몇 가지 질문이 있습니다. Metaphone Wiki 페이지에서 구현과 관련된 몇 가지 소스, 특히 MySQL 구현을 발견했습니다. 내가 테스트 데이터베이스를 가지고 테스트 해보고 싶었 기 때문에 metaphone.sql 파일 (double metaphone 함수 포함)을 처음으로 가져 왔습니다. here왜이 MySQL 이중 메타 폰 기능이 제대로 작동하지 않습니까?

바로 지금, 나는 모든 테이블을 갖고 있습니다. '이름'열에있는 국가, 예 : 'Afghanistan', 'Albania', 'Algeria'등등. 그래서, 먼저 실제로 각 나라의 Double Metaphone 문자열을 저장하기 위해 테이블에 새로운 열을 만들고 싶었습니다. 다음 코드를 실행했습니다 :

UPDATE country SET NameDM = dm(name) 

모두 제대로 작동했습니다. 아프가니스탄의 메타 폰 문자열은 'AFKNSTN', 알바니아는 'ALPN', 알제리는 'ALKR, ALJR'등입니다. "훌륭합니다."

그러나 테이블 쿼리를 시도 할 때 결과가 없습니다. metaphone.sql의 저자 당, 나는 다음과 같은 SQL 문의 구문을 준수 : 그래서

SELECT Name FROM tblPeople WHERE dm(Name) = dm(@search) 

, 나는 다음이 코드를 변경 : 물론

SELECT * FROM country WHERE dm(name) = dm(@search) 

, 나는 "변경 @ 검색 "을 찾고 있었지만 각 SQL 쿼리가 끝나면 결과는 0 점이됩니다.

누구든지이 문제를 설명 할 수 있습니까? 중요한 것을 놓친 건가요? 아니면 메타 폰 알고리즘을 오해 한 것입니까?

감사합니다.

+0

링크가 끊어졌습니다. –

+0

MySQL (및 Python) 코드가 GitHub에 있습니다. https://github.com/AtomBoy/double-metaphone – Andrew

답변

2

은 데이터 정렬/문자 집합/인코딩을 자세히 살펴 봅니다 (열 수준까지 정의 할 수 있음). 데이터 정렬은 문자열을 비교하는 방법을 정의하지만 문자 집합은 특정 데이터 정렬이 사용된다는 것을 암시 할 수 있습니다. 어쩌면 리터럴 문자열에 다른 문자 집합이있어 문자열 비교가 실패 할 수도 있습니다.

심지어이

select name, length(name), char_length(name), @search, length(@search), char_length(@search) from tbl 

를 공개 할 수있다.

show variables like 'character%' 

.

show create table tbl 
+0

도움을 주셔서 감사합니다. 내 '국가'테이블의 구조를 확인했습니다. 'name'열과 'NameDM'열은 모두 utf8_bin 데이터 정렬입니다. 해당 SELECT 쿼리를 실행 한 후 다음 결과가 나타납니다. [link] (http://i.imgur.com/PWGRI.png) 반면에 "show variables"쿼리는 다음을 반환합니다. [link] (http : //i.imgur.com/kvxZU.png). 따라서 이러한 문자 집합 중 일부는 utf8 대신 latin입니다. 윌 내 쿼리에 영향을 미칩니 까? – TimeBomb006

2
SELECT * FROM country WHERE NameDM = dm(@search) 

은 모든 국가에 대한 DM 검색을 할 때마다 계산되지 않도록 당신이 결국 원하는 아마입니다. 당신이 가지고 있었던 것은 그것이 일했어 야하는 것처럼 보인다. 다음을 수행하여 문제를 해결할 수 있습니다.

SELECT dm('Albania') 

... ALPN을 받아야합니다. 이제 무엇을 얻을 수 있습니까?

SELECT * FROM country WHERE NameDM = 'ALPN' 

?

+0

메타 폰 인코딩 저장에 대한 현명한 조언. – APC

3

dm() 출력을 비교할 때 다음과 같은 기능을 사용하여 더 많은 어지러운 정도를 허용합니다. 직접 검사 dm('smith') != dm('schmitt')은 내 이름의 일반적인 맞춤법 오류를 포함하여 많은 수의 이름에 대해 실패합니다.

이 함수는 각 반환 된 행의 순위를 매길 수있는 0.0과 1.0 사이의 일치 가중치를 만듭니다. 0.3은 이상한 발음을 캡처하는 데 아주 좋은 값이고, 0.5는 더 평범한 값입니다.

이 원래 문자열, 이것은 성능 문제입니다하지더블 메타 폰 문자열과 의 비교입니다 dmcompare(dm("boothroyd"), dm("boofreed")) = 0.3
dmcompare(dm("smith"), dm("scmitt")) = 0.5

공지 사항, 즉, 내 DB는 메타 폰에 대한 열을 포함 뿐만 아니라 원래 문자열.

 
    CREATE FUNCTION `dmcompare`(leftValue VARCHAR(55), rightValue VARCHAR(55)) 
     RETURNS DECIMAL(2,1) 
    NO SQL 
    BEGIN 
    --------------------------------------------------------------------------------------- 
    -- Compare two (double) metaphone strings for potential similarlity, i.e. 
    -- dm("smith") != dm("schmitt") :: "SM0;XMT" != "XMT;SMT" 
    -- dmcompare(dm('smith'), dm('schmitt') returns 0,5 
    -- @author: P.Boothroyd 
    -- @version: 0.9, 08/01/2013 
    -- The values here can still be played with 
    -- (c) GNU P L - feel free to share and adapt, but please acknowledge the original code 
    --------------------------------------------------------------------------------------- 
     DECLARE leftPri, leftSec, rightPri, rightSec VARCHAR(55) DEFAULT ''; 
     DECLARE sepPos INT; 
     DECLARE retValue DECIMAL(2,1); 
     DECLARE partMatch BOOLEAN; 

     -- Extract the metaphone tags 
     SET sepPos = LOCATE(";", leftValue); 
     IF sepPos = 0 THEN 
      SET sepPos = LENGTH(leftValue) + 1; 
     END IF; 
     SET leftPri = LEFT(leftValue, sepPos - 1); 
     SET leftSec = MID(leftValue, sepPos + 1, LENGTH(leftValue) - sepPos); 

     SET sepPos = LOCATE(";", rightValue); 
     IF sepPos = 0 THEN 
      SET sepPos = LENGTH(rightValue) + 1; 
     END IF; 
     SET rightPri = LEFT(rightValue, sepPos - 1); 
     SET rightSec = MID(rightValue, sepPos + 1, LENGTH(rightValue) - sepPos); 

     -- Calculate likeness factor 
     SET retValue = 0; 
     SET partMatch = FALSE; 
     -- Primaries equal 50% match 
     IF leftPri = rightPri THEN 
      SET retValue = retValue + 0.5; 
      SET partMatch = TRUE; 
     ELSE 
      IF SOUNDEX(leftPri) = SOUNDEX(rightPri) THEN 
       SET retValue = retValue + 0.3; 
       SET partMatch = TRUE; 
      END IF; 
     END IF; 
     -- Test alternate primary and secondaries, worth 30% match 
     IF leftSec = rightPri THEN 
      SET retValue = retValue + 0.3; 
      SET partMatch = TRUE; 
      IF SOUNDEX(leftSec) = SOUNDEX(rightPri) THEN 
       SET retValue = retValue + 0.2; 
       SET partMatch = TRUE; 
      END IF; 
     END IF; 
     -- Test alternate primary and secondaries, worth 30% match 
     IF leftPri = rightSec THEN 
      SET retValue = retValue + 0.3; 
      SET partMatch = TRUE; 
      IF SOUNDEX(leftPri) = SOUNDEX(rightSec) THEN 
       SET retValue = retValue + 0.2; 
       SET partMatch = TRUE; 
      END IF; 
     END IF; 
     -- Are secondary values the same or both NULL 
     IF leftSec = rightSec THEN 
      -- No secondaries ... 
      IF leftSec = '' THEN 
       -- If there is prior matching then no secondaries is 40% 
       IF partMatch = TRUE THEN 
        SET retValue = retValue + 0.4; 
       END IF; 
      ELSE 
       -- If the secondaries match then 50% match 
       SET retValue = retValue + 0.5; 
      END IF; 
     ELSE 
      IF SOUNDEX(leftSec) = SOUNDEX(rightSec) THEN 
       IF leftSec = '' THEN 
        IF partMatch = TRUE THEN 
         SET retValue = retValue + 0.3; 
        END IF; 
       END IF; 
      END IF; 
     END IF; 
     RETURN (retValue); 
    END 

코드 번째 사용 주시기 바랍니다뿐만 아니라 이 코드에 대한 어떤 용도로 P.Boothroyd 소스를 언급 해주십시오 - 등, 즉 변화하는 값을

환호, 폴