2014-07-16 28 views
0

我们在公司名称字段上使用全文索引搜索。全文索引中的关键字搜索导致结果不能回来

我们使用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(); 
} 

我们想的话打出搜索,然后concatonate在一起一个和搜索。这意味着,像“我的公司”这样的查询将实际上针对“我的​​”和“公司”的索引进行搜索。

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

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

一切都很好,直到你开始添加“关键词”。到目前为止,我们已经计算出,或者或者不包含在搜索返回0结果中。没有错误,只是没有结果。

以下是我们将某些词语“黑名单”排除在搜索查询之外的方法。

​​

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

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

编辑:

一对夫妇的其他情形

如果我不按摩搜索字符串可言,对单词搜索“不”导致错误“空或空全文谓词。”

同样的情况下,只是应用字符串,如果我使公司“公司不删除”,任何版本的字符串中有或没有返回0结果。

回答

0

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

首先,我们有一个业务规则,要求搜索包括&符号。全文索引似乎丢掉了&,导致返回结果不正确。所以,我不得不特殊情况下任何&搜索使用类似的语句。

我离开我的代码做了上面的操作,在那里它解析出单词的黑名单并尝试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; 
}