看来,如果要搜索多部分名称,全文搜索是最简单最合适的方法(如果我错了,请纠正我)。另一种选择是LIKE '%query%'
,但是它有太多缺点:
- 糟糕的性能,因为它进行索引扫描
- 术语顺序很重要,例如 - 搜索“John Smith”和“Smith John”将返回不同的结果。
- 它不考虑单词边界,例如 - 搜索“Ann”也将检索“Joanna”和“Danny”,它们不是有用的匹配项。
所以我继续执行全文搜索。我的查询看起来像这样:
SELECT * FROM Users WHERE CONTAINS(Name, '"John*"')
唯一的小困难是我必须将用户查询(John)转换为对 CONTAINS 友好的查询(“John*”)。为此,我在我的 UserRepository 中实现了这个方法:
/// <summary>
/// Converts user-entered search query into a query that can be consumed by CONTAINS keyword of SQL Server.
/// </summary>
/// <example>If query is "John S Ju", the result will be "\"John*\" AND \"S*\" AND \"Ju*\"".</example>
/// <param name="query">Query entered by user.</param>
/// <returns>String instance.</returns>
public static string GetContainsQuery(string query)
{
string containsQuery = string.Empty;
var terms = query.Split(new[] { ' ' }, StringSplitOptions.None);
if (terms.Length > 1)
{
for (int i = 0; i < terms.Length; i++)
{
string term = terms[i].Trim();
// Add wildcard term, e.g. - "term*". The reason to add wildcard is because we want
// to allow search by partially entered name parts (partially entered first name and/or
// partially entered last name, etc).
containsQuery += "\"" + term + "*\"";
// If it's not the last term.
if (i < terms.Length - 1)
{
// We want all terms inside user query to match.
containsQuery += " AND ";
}
}
containsQuery = containsQuery.Trim();
}
else
{
containsQuery = "\"" + query + "*\"";
}
return containsQuery;
}
希望这可以帮助任何遇到同样问题的人。
PS - 我写了一篇博文来记录这一点。