2009-11-22 3 views
4

빠른 MYSQL/PHP 질문. , 나는을 강조하기 위해 PHP를 사용하고 지금PHP/MySQL : "SOUNDS LIKE"쿼리 결과 강조 표시

foreach($find_array as $word) { 
    clauses[] = "(firstname SOUNDS LIKE '$word%' OR lastname SOUNDS LIKE '$word%')"; 
} 
if (!empty($clauses)) $filter='('.implode(' AND ', $clauses).')'; 
$query = "SELECT * FROM table WHERE $filter"; 

: 어떤 결과가 일반 검색 쿼리 발견되지 않으면 나는의 조정, 대체로 "그다지 엄격하지"검색 쿼리를 사용하고 있습니다 결과는 다음과 같습니다.

foreach ($find_array as $term_to_highlight){ 
    foreach ($result as $key => $result_string){ 
     $result[$key]=highlight_stuff($result_string, $term_to_highlight); 
    } 
} 

그러나이 방법은 무엇을 강조해야할지 모를 때 엉망입니다. 해당 mysql 쿼리를 실행할 때 "소리 같은"일치 항목이 무엇인지 알아낼 수있는 방법이 있습니까?

즉, 누군가가 "조안"을 검색하면 "존"을 대신 강조하고 싶습니다.

+1

아마도 SELECT * FROM 테이블 WHERE $ clauses는 SELECT * FROM 테이블 WHERE $ filter입니까? – Eineki

+0

어, 예 - 죄송합니다. 나는 가지고있는 스크립트의 끔찍한 엉망을 단순화하려고 노력했다. – Greg

답변

6

SOUND LIKE 조건은 두 단어의 SOUNDEX 키를 비교하기 만하면 PHP soundex() 함수를 사용하여 동일한 키를 생성 할 수 있습니다.

일치하는 행을 찾고 강조 표시 할 단어를 찾지 못한 경우 firstname과 lastname을 모두 가져온 다음 PHP를 사용하여 일치하는 단어를 찾고 해당 단어 만 강조 표시 할 수 있습니다.

나는 이것을 시험해보기 위해이 코드를 만들었습니다. 내가 그것을 이해하고있는 경우,

<?php 
/** 
* Attempts to find the first word in the $heystack that is a soundex 
* match for the $needle. 
*/ 
function find_soundex_match($heystack, $needle) { 
    $words = explode(' ', $heystack); 
    $needle_soundex = soundex($needle); 
    foreach($words as $_word) { 
     if(soundex($_word) == $needle_soundex) { 
      return $_word; 
     } 
    } 
    return false; 
} 
?> 

어느 : 은 같이 할 수있는 문자열에서 일치하는 SOUNDEX 단어를 꺼내

<?php 
// A space seperated string of keywords, presumably from a search box somewhere. 
$search_string = 'John Doe'; 

// Create a data array to contain the keywords and their matches. 
// Keywords are grouped by their soundex keys. 
$data = array(); 
foreach(explode(' ', $search_string) as $_word) { 
    $data[soundex($_word)]['keywords'][] = $_word; 
} 

// Execute a query to find all rows matching the soundex keys for the words. 
$soundex_list = "'". implode("','", array_keys($data)) ."'"; 
$sql = "SELECT id, firstname, lastname 
     FROM sounds_like 
     WHERE SOUNDEX(firstname) IN({$soundex_list}) 
     OR  SOUNDEX(lastname) IN({$soundex_list})"; 
$sql_result = $dbLink->query($sql); 

// Add the matches to their respective soundex key in the data array. 
// This checks which word matched, the first or last name, and tags 
// that word as the match so it can be highlighted later. 
if($sql_result) { 
    while($_row = $sql_result->fetch_assoc()) { 
     foreach($data as $_soundex => &$_elem) { 
      if(soundex($_row['firstname']) == $_soundex) { 
       $_row['matches'] = 'firstname'; 
       $_elem['matches'][] = $_row; 
      } 
      else if(soundex($_row['lastname']) == $_soundex) { 
       $_row['matches'] = 'lastname'; 
       $_elem['matches'][] = $_row; 
      } 
     } 
    } 
} 

// Print the results as a simple text list. 
header('content-type: text/plain'); 
echo "-- Possible results --\n"; 

foreach($data as $_group) { 
    // Print the keywords for this group's soundex key. 
    $keyword_list = "'". implode("', '", $_group['keywords']) ."'"; 
    echo "For keywords: {$keyword_list}\n"; 

    // Print all the matches for this group, if any. 
    if(isset($_group['matches']) && count($_group['matches']) > 0) { 
     foreach($_group['matches'] as $_match) { 
      // Highlight the matching word by encapsulatin it in dashes. 
      if($_match['matches'] == 'firstname') { 
       $_match['firstname'] = "-{$_match['firstname']}-"; 
      } 
      else { 
       $_match['lastname'] = "-{$_match['lastname']}-"; 
      } 

      echo " #{$_match['id']}: {$_match['firstname']} {$_match['lastname']}\n"; 
     } 
    } 
    else { 
     echo " No matches.\n"; 
    } 
} 
?> 

더 일반화 된 기능, (내 이론의 xD을 테스트했다) 정확하게, 이전에 게시 된 코드에서 다음과 같이 사용할 수 있습니다.

이 코드는 첫 번째 sni ppet.

+0

정말 고마워요! – Greg

8

SOUNDS LIKE은 생각대로 작동하지 않습니다. % 와일드 카드를 지원하지 않으므로 MySQL의 LIKE과 동일하지 않습니다.

"John"을 검색 할 때 검색어가 "John David"를 찾지 못한다는 의미입니다. 이것은 단지 당신의 후퇴 인 경우에 받아 들여질 수도 있지만, 이상적이지는 않습니다.

그래서 (개선이 필요한) 다른 제안이 있습니다. 먼저 soundex() PHP를 사용하여 찾고있는 키워드의 soundex를 찾으십시오.

$soundex = soundex($word); 
$soundexPrefix = substr($soundex, 0, 2); // first two characters of soundex 
$sql = "SELECT lastname, firstname ". 
    "FROM table WHERE SOUNDEX(lastname) LIKE '$soundexPrefix%' ". 
    "OR SOUNDEX(firstname) LIKE '$soundexPrefix%'"; 

이제 소리의 모호한 유사성 (이 많은 항목이 될 수있다 firstnames과 라스트 네임의 목록을해야합니다, 당신은 당신이 당신의 검색에 사용하는 SOUNDEX 접두사의 길이를 늘릴 수 있습니다). 그런 다음 각 단어의 soundex와 검색어 사이의 Levenshtein 거리를 계산하고이를 기준으로 정렬 할 수 있습니다.

둘째, SQL 주입 버그를 피하기 위해 MySQL의 매개 변수화 된 쿼리를 살펴 봐야합니다.

+0

이것을 지적 해 주셔서 감사합니다."John"은 필자의 경우 "John David"와 일치합니다. 나는 단어로 쿼리를 분해하고 내가 검색하는 모든 필드에 대해 각각을 검사하고있다. 마찬가지로, "검색 결과 문자열이"John David "인 경우"WHERE (lastname SOUNDS LIKE 'John'또는 SOUNDS LIKE 'John') AND (lastname SOUNDS LIKE 'David'OR SOUNDS LIKE 'David' , AND보다 앞의 첫 번째 부분 만 수행하므로 일치합니다 아마도 가장 효율적인 방법은 아닐까요? – Greg

+0

예, 아마도 그렇습니다. 그런 다음 내 솔루션은 실제로 존재하지 않는 문제에 대한 해결 방법이됩니다. ... :) –