Xem bài viết này cho cách bạn có thể implement Levenshtein distance in a MySQL stored function.
Đối với hậu thế, gợi ý của tác giả là để làm điều này:
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;
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
Ông cũng cung cấp một phương pháp helper LEVENSHTEIN_RATIO đó sẽ đánh giá tỷ lệ tổng ký tự/khác nhau, chứ không phải là một chỉnh sửa khoảng cách thẳng. Ví dụ, nếu nó là 60%, thì ba phần năm các ký tự trong từ nguồn khác với từ đích.
CREATE FUNCTION LEVENSHTEIN_RATIO (s1 VARCHAR(255), s2 VARCHAR(255))
RETURNS INT
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
Ngoài ra với hậu thế, đây là mã của Jason Rust dựa trên mã của Arnold Fribble, lần lượt, một phần dựa trên công việc của Joseph Gama. – webbiedave
D'oh. Bằng cách nào đó tôi nghĩ rằng tôi đã đề cập đến tác giả, nhưng rõ ràng là tôi đã không. Cảm ơn bạn đã điền vào các khoảng trống, @webbiedave. –
Cảm ơn UDF, nó rất hữu ích. Nhưng nếu tôi chạy một truy vấn như "SELECT * FROM bảng WHERE HAVING LEVENSHTEIN ('từ khóa', trường) <3 (hoặc hơn)" trên một bảng hàng ~ 300k, nó (rõ ràng) mất độ tuổi để hoàn thành. Tôi cũng đã thử giảm các hàng tìm kiếm bên trong (sử dụng WHERE CHAR_LENGTH ('field') GIỮA CHAR_LENGTH ('keyword') - 1 AND CHAR_LENGTH ('keyword') + 1) nhưng nó trả về kết quả trong whopping 35 seconds :) Bạn (hoặc những người khác) có ý tưởng tăng tốc truy vấn này? – Hazar