全文搜索适合搜索人名吗?

我有一个用户名单中有一列的用户表:

CREATE TABLE [dbo].[Users]
(
    Id bigint NOT NULL,
    Name nvarchar(80) NOT NULL,
    PRIMARY KEY CLUSTERED (Id ASC)
)

Name列可以包含全名或只是名字或任何真正的名称(用空格分隔)。 为了实现对Name的搜索,我想利用SQL的全文搜索,但不确定它是否适合搜索名称/昵称而不是实际的单词。 另外问题是 - 在Name上创建FT索引时选择哪种语言?

任何其他考虑?

谢谢。


乍一看,我会推荐使用LIKE运算符而不是全文查询。

确保搜索不区分大小写,可能不区分重音。 这可以通过在服务器,数据库,表列或查询中设置正确的排序规则来实现。 在查询中,这是通过如下方式完成的:

SELECT *
FROM [dbo].[Users]
WHERE Name LIKE '%niaher%' COLLATE SQL_Latin1_General_CP1_CI_AI

如果您使用全文索引,则可以获得各种功能,例如动词词干和同义词库,请参阅全文搜索中的语言组件和语言支持,在名称列表中进行搜索时,您不需要这些功能。 顺便说一下,这些功能是依赖于语言的,这就是为什么您要在全文索引中指定一种语言的原因。

应用您可能要避免的停用列表。 至少我会,因为在荷兰的许多姓氏开始与物品和/或介词:“ 伦勃朗 ”。 “van”肯定会在荷兰的名单中,并阻止包含“van”的搜索字词匹配。

如果遇到性能问题,尝试全文索引和使用CONTAINS进行简单术语搜索可能会很有用。

SELECT *
FROM [dbo].[Users]
WHERE CONTAINS(Name, 'niaher')

请注意,全文索引是异步更新的。


看起来,如果你想搜索多部分名称,全文搜索是最简单和最合适的方法(请纠正我,如果我错了)。 另一种选择是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 - 我写了一篇博文来记录这一点。

    链接地址: http://www.djcxy.com/p/11465.html

    上一篇: Is full text search suitable for searching people's names?

    下一篇: Tips to shift from App Inventor to Eclipse