2014-07-16 53 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; 
}