尋找模糊弦函數的近似匹配
小提示
有關更多詳細信息,請參閱 文本和圖像 選項卡!
真實世界的數據很少能完全吻合。 顧客名稱可能拼錯、地址縮寫不同,或產品描述輸入不一致。 模糊字串匹配功能能幫助你找到相似但不完全相同的紀錄,從而提升資料品質、重複偵測及更靈活的搜尋功能。
了解字串相似度的概念
模糊匹配演算法透過計算兩個字串之間的差異來測量它們的相似度。 目前有兩種主要方法被廣泛使用:
編輯距離(Levenshtein 距離) 計算將一個字串轉換成另一個字串所需的最少單字元操作次數(插入、刪除、替換)。 數值越低表示弦數較相似。
相似度分數 以百分比或比率表示字串間的關係,數值越高表示相似度越高。
請考慮下列範例:
- 「color」→「colour」:編輯距離 = 1(插入 'u')
- "database" → "databaes": edit distance = 2 (swap 'e' and 's')
- 「Microsoft」→「Microsft」:編輯距離 = 1(刪除 'o')
備註
模糊匹配比對計算成本高於精確匹配。 策略性地使用它,通常用於已依據其他條件預先篩選過的候選集。
計算編輯距離 EDIT_DISTANCE
該 EDIT_DISTANCE 函數回傳兩字串間的 Levenshtein 距離,這是將一個字串轉換為另一字串所需的最少編輯次數。 目標是根據定義的閾值找到相似的字串。
以下範例示範如何使用 EDIT_DISTANCE:
SELECT
EDIT_DISTANCE('color', 'colour') AS ColorVariant, -- Returns 1
EDIT_DISTANCE('database', 'databaes') AS Typo, -- Returns 2
EDIT_DISTANCE('SQL Server', 'SQL Server') AS Exact, -- Returns 0
EDIT_DISTANCE('hello', 'world') AS Different; -- Returns 4
你可以用 EDIT_DISTANCE 來查找即使有些微差異,也可能重複或相符的紀錄:
-- Find customers with similar names to a search term
DECLARE @searchName NVARCHAR(100) = 'Jon Smith';
SELECT
CustomerID,
FirstName,
LastName,
FirstName + ' ' + LastName AS FullName,
EDIT_DISTANCE(@searchName, FirstName + ' ' + LastName) AS EditDistance
FROM SalesLT.Customer
WHERE EDIT_DISTANCE(@searchName, FirstName + ' ' + LastName) <= 3
ORDER BY EDIT_DISTANCE(@searchName, FirstName + ' ' + LastName);
此外,你也可以找到可能重複的產品:
-- Find product pairs with similar names
SELECT
p1.ProductID AS Product1ID,
p1.Name AS Product1Name,
p2.ProductID AS Product2ID,
p2.Name AS Product2Name,
EDIT_DISTANCE(p1.Name, p2.Name) AS EditDistance
FROM SalesLT.Product AS p1
INNER JOIN SalesLT.Product AS p2
ON p1.ProductID < p2.ProductID
WHERE EDIT_DISTANCE(p1.Name, p2.Name) <= 5
ORDER BY EDIT_DISTANCE(p1.Name, p2.Name);
小提示
最大有意義的編輯距離取決於字串長度。 對於短字串(5-10 個字元),編輯距離為 1-2 表示相似度。 如果弦比較長,你可以允許距離在3到5之間。
衡量與EDIT_DISTANCE_SIMILARITY的相似度
EDIT_DISTANCE_SIMILARITY 回傳 0 到 100 之間的標準化相似度分數,其中 100 代表相同的字串。 這種基於百分比的指標比原始編輯距離更容易解讀,尤其是在比較不同長度字串時:
SELECT
EDIT_DISTANCE_SIMILARITY('color', 'colour') AS ColorSimilarity, -- ~85
EDIT_DISTANCE_SIMILARITY('database', 'databaes') AS TypoSimilarity, -- ~75
EDIT_DISTANCE_SIMILARITY('SQL', 'SQL Server') AS PartialMatch, -- ~30
EDIT_DISTANCE_SIMILARITY('hello', 'hello') AS Exact; -- 100
你可以利用相似度分數尋找具有閾值的近似匹配,如下範例:
-- Find products similar to a search term (at least 70% similar)
DECLARE @searchTerm NVARCHAR(100) = 'Mountain Bike Frame';
SELECT
ProductID,
Name,
EDIT_DISTANCE_SIMILARITY(@searchTerm, Name) AS SimilarityScore
FROM SalesLT.Product
WHERE EDIT_DISTANCE_SIMILARITY(@searchTerm, Name) >= 70
ORDER BY EDIT_DISTANCE_SIMILARITY(@searchTerm, Name) DESC;
使用JARO_WINKLER_DISTANCE計算語音相似度
Jaro-Winkler 演算法設計用於比較名稱與短字串。 它會給從一開始就匹配的字串較高分數,使得對於前綴較為重要的人名來說非常有效:
SELECT
JARO_WINKLER_DISTANCE('MARTHA', 'MARHTA') AS NameTypo, -- ~0.96
JARO_WINKLER_DISTANCE('JONES', 'JOHNSON') AS SimilarNames, -- ~0.83
JARO_WINKLER_DISTANCE('JOHN', 'JON') AS NameVariant, -- ~0.93
JARO_WINKLER_DISTANCE('SMITH', 'SMYTH') AS SpellingVar; -- ~0.96
Jaro-Winkler 分數範圍為0到1,1代表相同的字串。 分數高於0.9通常表示名字匹配度強。
以下範例是尋找與搜尋輸入相似名字的客戶:
-- Find customers with names similar to a search
DECLARE @searchFirst NVARCHAR(50) = 'John';
DECLARE @searchLast NVARCHAR(50) = 'Smythe';
SELECT
CustomerID,
FirstName,
LastName,
JARO_WINKLER_DISTANCE(@searchFirst, FirstName) AS FirstNameScore,
JARO_WINKLER_DISTANCE(@searchLast, LastName) AS LastNameScore,
(JARO_WINKLER_DISTANCE(@searchFirst, FirstName) +
JARO_WINKLER_DISTANCE(@searchLast, LastName)) / 2 AS CombinedScore
FROM SalesLT.Customer
WHERE JARO_WINKLER_DISTANCE(@searchFirst, FirstName) > 0.85
AND JARO_WINKLER_DISTANCE(@searchLast, LastName) > 0.85
ORDER BY CombinedScore DESC;
備註
Jaro-Winkler 是針對短字串如名字進行優化的。 對於較長的字串,如地址或描述, EDIT_DISTANCE_SIMILARITY 通常會有更好的結果。
效能考量
模糊匹配函數會檢查兩個字串中的每個字元,因此計算量極高。 精確字串比較可在字元差異後立即停止,索引查找則使用高效的 B 樹遍歷。 相較之下,模糊演算法必須逐字元計算相似度分數。 對於一個有 1,000,000 列的資料表,未優化的模糊搜尋可能會進行 1,000,000 次相似度計算,每次都涉及數十次字元比較。
高效模糊匹配的關鍵是在應用昂貴的模糊函數前先減少候選集。 使用具有 LIKE 模式的索引欄位、相關欄位的精確匹配或範圍篩選器來首先縮小結果範圍。 只有在這時,才對較小的候選集合套用模糊匹配。
以下範例展示了這種漸進式過濾方法:
-- Not good: Fuzzy match against entire table
SELECT * FROM LargeCustomerTable
WHERE EDIT_DISTANCE_SIMILARITY('John Smith', FullName) > 70;
-- Better: Pre-filter before fuzzy matching
SELECT * FROM LargeCustomerTable
WHERE FullName LIKE 'J%' -- First letter filter
AND EDIT_DISTANCE_SIMILARITY('John Smith', FullName) > 70;
-- Best: Use multiple pre-filters
SELECT * FROM LargeCustomerTable
WHERE FirstName LIKE 'Jo%'
AND LastName LIKE 'Sm%'
AND JARO_WINKLER_DISTANCE('John', FirstName) > 0.85
AND JARO_WINKLER_DISTANCE('Smith', LastName) > 0.85;
這很重要
像 EDIT_DISTANCE、 EDIT_DISTANCE_SIMILARITY、 JARO_WINKLER_DISTANCE 和 這類模糊字串匹配函數可在 SQL Server 2025 及以後版本、Azure SQL 資料庫,以及 Microsoft Fabric 中的 SQL 資料庫中使用。 請查看你平台的文件以了解具體功能可用性。
欲了解更多模糊字串匹配的資訊,請參見 字串函數。