Mysqlのストアードファンクションでレーベンシュタイン距離を利用する

使用目的としては、通常通り検索した後mysql内で検索語とタイトルのレーベンシュタイン距離を基準に並び替えたい
レーベンシュタイン距離の計算はStored Function(ストアード・ファンクション)として実装

http://ja.wikipedia.org/wiki/%E3%83%AC%E3%83%BC%E3%83%99%E3%83%B3%E3%82%B7%E3%83%A5%E3%82%BF%E3%82%A4%E3%83%B3%E8%B7%9D%E9%9B%A2
http://php.benscom.com/manual/ja/function.levenshtein.php
http://eringi.com/weblog/archives/2009/05/mysql_levenshtein.html
http://www.assembla.com/wiki/show/winvictory/Levenshtein_SQL_code

設定

以下をmysqlで実行する

|sql|
DELIMITER $$

CREATE DEFINER=`root`@`localhost` FUNCTION `levenshtein`(s1 VARCHAR(255), s2 VARCHAR(255)) RETURNS int(11)  
    DETERMINISTIC  
BEGIN  
        DECLARE s1_len, s2_len, i, j, c, c_temp, cost INT;  
        DECLARE s1_char CHAR;  
        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 $$

CREATE DEFINER=`root`@`localhost` FUNCTION `levenshtein_ratio`(s1 VARCHAR(255), s2 VARCHAR(255)) RETURNS int(11)  
    DETERMINISTIC  
BEGIN  
        DECLARE s1_len, s2_len, max_len INT;  
        SET s1_len = LENGTH(s1), s2_len = LENGTH(s2);  
        IF s1_len > s2_len THEN SET max_len = s1_len; ELSE SET max_len = s2_len; END IF;  
        RETURN ROUND((1 - LEVENSHTEIN(s1, s2) / max_len) * 100);  
      END $$

DELIMITER ;

||<

使い方

|sql|
ORDER LEVENSHTEIN_RATIO(FIELD_TITLE, 'キーワード') DESC
||<