2011-06-11 3 views
6

나는 mysql에 1000000 개 이상의 이름을 저장하고있는 데이터베이스를 가지고있다. 이제는 내 응용 프로그램의 작업이 약간 일반적입니다. 나는 데이터베이스에서 이름을 검색 할뿐만 아니라 유사한 이름을 찾습니다. 이름이 christian으로 입력되면 응용 프로그램에 christine, chris 등과 같은 제안 된 이름이 표시됩니다. like 절을 사용하지 않고이를 수행하는 최적의 방법은 무엇입니까? 제안 사항은 이름의 마지막 부분의 변경 사항에만 적용됩니다.큰 테이블에서 비슷한 값을 찾는 최적의 방법

+0

왜 'like' 절을 사용하지 않으시겠습니까? – Geoffroy

+0

Postgres 로의 전환을 고려하십시오. [텍스트 검색 사전] (http://www.postgresql.org/docs/9.0/static/textsearch-dictionaries.html)을 사용하여이 작업을 수행 할 수 있습니다. –

+0

새 필드를 추가 할 수 있습니까? 그렇다면 내 대답 아래에 내 추가 의견을 확인하십시오. –

답변

5

는 : http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_soundex

그렇지 않으면 … LIKE 'chri%' 나쁜 생각하지 나를 위해 보인다?

LIKE없이 첫 번째 문자 만 사용하려는 경우 SUBSTRING()을 사용할 수 있습니다.

+0

나는 이것을 한 번 두 번 upvote 할 수 있으면 좋겠다. 물론 SUBSTRING()을 사용하여 첫 번째 문자 만 비교하는 경우 LIKE xyz %는 동일한 작업을 수행하는 것으로 보입니다. 그러나 SOUNDEX() ... 그것은 훌륭한 제안이며 나에게 Lingua :: EN :: SimilarNames, Text :: Soundex, Lingua :: EN :: NameLookup CPAN 모듈을 생각 나게합니다. 먼저 데이터 집합을 가져 오도록 요구하십시오.) – DavidO

+1

SUBSTRING()을 사용하려면 전체 테이블 스캔이 필요합니다. LIKE는이 경우 더 빠릅니다. SOUNDEX()는 좋은 제안이지만 검색이 빠르기 때문에 별도의 색인 필드로 저장해야합니다. –

0

정규 표현식을 사용할 수 있습니다. 나는 thôme에 goot 아니지만 WHERE 절에 넣을 수있는 REGEXP라는 함수가 있습니다. Look here

+0

'REGEXP'는 좀 더 복잡한 질의에 편리하지만'LIKE'보다 훨씬 느립니다. – glortho

+0

나는 (나는 결코 그것을 사용하지 않았다) 단지 "LIKE"와 다른 것을 제안했다는 것을 상상했다! –

1

Like 일반적으로 좋은 해결책이지만 성능을 향상시키는 또 다른 방법은 부분적인 열 인덱스를 만든 다음 접두사와 동일한 길이로 쿼리를 제출하는 것입니다. col_name(length)에 대해서는 MySQL documentation을 참조하십시오. 당신이 (소리) 비슷한 이름 SOUNDEX() 같은 것이 도움이 될 수도합니다

0

SOUNDS LIKE를 사용할 수 있지만 상당히 빠르다고 생각합니다.

http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#operator_sounds-like

+1

kalyoncu,이 작업은 효과적 일 수 있지만 SOUNDEX()와 같은 전체 테이블 검사가 필요합니다. –

+0

추가 필드를 만들 수 있으면이를 피할 수 있습니다. 각 삽입물을 사용하여 해당 필드에 soundex를 삽입하면 검색 속도가 빨라집니다. 또한 해당 필드에 색인을 작성할 수 있습니다. 흠, 이전보다 더 나은 대답이라고 생각합니다. –

+0

soundex 문자열을 숫자로 변환 할 수도 있습니다. 정확하게 기억한다면 C#### 형식입니다. 여기서 C는 1-26 사이이므로 6 자리 숫자입니다. –

0

왼쪽 테이블 검사를 요구하지 않을 것이다 고정된다 LIKE 사용. 나는 이것이 당신이 LIKE를 사용하기를 원하지 않는 이유라고 가정하고있다 : SELECT * FROM table WHERE name LIKE CONCAT(?, "%")은 빠르며 행을 찾기 위해 테이블 ​​스캔을 요구하지 않을 것이다. CONCAT을 사용하면 % 구문으로 준비된 쿼리를 사용할 수 있습니다. 정렬 된 목록에있는 이웃을 찾아

SELECT * from table WHERE name < 'christian' LIMIT 20

SELECT * FROM table WHERE name > 'christian' LIMIT 20

:

또한 뭔가를 할 수 있습니다.

2

php의 metaphone() 함수를 사용하여 각 이름에 대한 메타 폰 코드를 생성하고 이름과 함께 저장할 수 있습니다.

<?php 
print "chris" . "\t" . metaphone("chris") . "\n"; 
print "christian" . "\t" . metaphone("christian") . "\n"; 
print "christine" . "\t" . metaphone("christine") . "\n"; 

# prints: 
# chris  XRS 
# christine XRSTN 
# christian XRSXN 

넌 다음 levenshtein 거리 알고리즘을 사용할 수있다 (하나의 PHP [http://php.net/manual/en/function.levenshtein.php] 또는 MySQL의 [http://www.artfulsoftware.com /infotree/queries.php#552]) metacodes 사이의 거리를 계산합니다. 아래의 테스트에서 2 이하의 거리는 당신이 찾고있는 유사성의 수준을 나타내는 것처럼 보였습니다.

<?php 
$names = array(
     array('mike',metaphone('mike')), 
     array('chris',metaphone('chris')), 
     array('chrstian',metaphone('christian')), 
     array('christine',metaphone('christine')), 
     array('michelle',metaphone('chris')), 
     array('mick',metaphone('mick')), 
     array('john',metaphone('john')), 
     array('joseph',metaphone('joseph')) 
); 

foreach ($names as $name) { 
     _compare($name); 
} 

function _compare($n) { 
     global $names; 
     $name = $n[0]; 
     $meta = $n[1]; 

     foreach ($names as $cname) { 
       printf("The distance between $name and {$cname[0]} is %d\n",       
        levenshtein($meta, $cname[1])); 
     } 
} 
관련 문제