【问题标题】:Keywords in Full Text Index Searching causing results to not come back全文索引搜索中的关键字导致结果不回来
【发布时间】:2014-07-16 18:00:18
【问题描述】:

我们正在对公司名称字段使用全文索引搜索。

我们将 EF 用于数据层,我被要求不要使用存储过程。

这是我的数据访问层中的方法:

public Task<List<Company>> SearchByName(string searchText)
{
        return DataContext.Company.SqlQuery(
            "select CompanyId AS Id, * from Company.Company AS c where contains(c.Name, @SearchText)",
            new SqlParameter("@SearchText", ParseSearchTextForMultiwordSearch(searchText)))
        .ToListAsync();
}

我们想在搜索中拆分单词,然后将它们连接在一起进行 AND 搜索。这意味着像“My Company”这样的查询实际上会针对“My”和“Company”这两个词的索引进行搜索。

此代码为上面的选择查询合并术语。

public string ParseSearchTextForMultiwordSearch(string searchText)
{
    var words = GetValidSearchTerms(searchText);
    var quotedWords = words.Select(x => string.Format("\"{0}*\"", x));
    return string.Join(" AND ", quotedWords);
}

在您开始添加“关键词”之前,一切都很好。到目前为止,我们已经弄清楚了and,or,or not included in a search return 0 results。没有错误,只是没有结果。

这是我们将某些单词“列入黑名单”的方法,以便将它们排除在搜索查询之外。

private static List<string> GetValidSearchTerms(string searchText)
{
    //AND and OR are keywords used by SQL Server Full Text Indexing.
    var blacklist = new string[] {
        "and",
        "or",
        "not"
    };

    //Filter them out here
    var words = searchText.Split(' ');

    var validWords = words.Where(x => !blacklist.Contains(x));

    return validWords.ToList();
}

问题是我们刚刚发现了另一个似乎导致问题的“关键字”。 “做”导致没有结果返回。我可以将它添加到黑名单中,但随着它的发展,我开始觉得处理这个问题的方法是错误的。

有没有更好的方法来处理这个问题?

编辑:

其他几个场景

如果我根本不处理搜索字符串,搜索单词“not”会导致错误“Null or empty full-text predicate。”

同样的场景,只是按原样应用字符串,如果我将公司设为“Company Do Not Delete”,则字符串中包含 Do 或 Not 的任何版本都会返回 0 个结果。

【问题讨论】:

    标签: c# sql-server-2012 full-text-search entity-framework-6


    【解决方案1】:

    我发布这个问题已经有一段时间了,经过几次迭代后,我想出了一些适合我们需求的搜索逻辑。

    首先,我们有一个业务规则,要求搜索包含一个 & 符号。全文索引似乎放弃了 &,使得返回的结果不正确。因此,我必须对任何 & 搜索进行特殊处理,以使用 like 语句。

    我让我的代码按照上面的方法解析单词的黑名单并尝试 CONTAINS 搜索。如果由于某种原因失败,我会改为执行 FREETEXT 搜索。

    public async Task<List<Company>> SearchByName(string searchText)
    {
        var results = new List<Company>();
    
        if (string.IsNullOrWhiteSpace(searchText))
            return results;
    
        if (searchText.IndexOf("&") >= 0)
        {
            var likeQuery = string.Format("%{0}%", searchText);
    
            results = await DataContext.Company.SqlQuery("SELECT CompanyId AS Id, IsEligible AS IsReadOnly, *" +
                                    "  FROM Company.Company AS con" +
                                    "  WHERE con.Name LIKE @SearchText",
                new SqlParameter("@SearchText", likeQuery))
                .ToListAsync();
        }
        else
        {
            var terms = ParseSearchTextForMultiwordSearch(searchText);
    
            if (string.IsNullOrWhiteSpace(terms))
                return results;
    
            // SqlQuery does not take any column mappings into account (https://entityframework.codeplex.com/workitem/233)
            // So we have to manually map the columns in the select statement
            var sqlQueryFormat = "SELECT CompanyId AS Id, IsEligible AS IsReadOnly, *" +
                                    "  FROM Company.Company AS con" +
                                    "  WHERE {0}(con.Name, @SearchText)";
    
            var sqlQuery = string.Format(sqlQueryFormat, "CONTAINS");
            var errored = false;
    
            try
            {
                results = await DataContext.Company.SqlQuery(sqlQuery,
                new SqlParameter("@SearchText", terms))
                .ToListAsync();
            }
            catch
            {
                //catch the error but do nothing with it
                errored = true;
            }
    
            //when the contains search fails due to some unknown error, use Freetext as a backup
            if (errored)
            {
                sqlQuery = string.Format(sqlQueryFormat, "FREETEXT");
    
                results = await DataContext.Company.SqlQuery(sqlQuery,
                new SqlParameter("@SearchText", terms))
                .ToListAsync();
            }
        }
    
        return results;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-11-10
      • 2017-06-09
      • 1970-01-01
      • 1970-01-01
      • 2014-12-16
      • 1970-01-01
      • 2023-01-11
      • 1970-01-01
      相关资源
      最近更新 更多