2014-07-16 3 views
0

회사 이름 필드에서 전체 텍스트 색인 검색을 사용하고 있습니다.전체 텍스트 색인의 키워드 검색 결과가 돌아 오지 않는 검색

데이터 레이어에 EF를 사용하고 있으며 저장된 procs를 사용하지 않도록 요청 받았습니다.

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 싶었다 : 여기

내 데이터 액세스 레이어의 방법이다. 즉, "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); 
} 

"키워드"를 추가하기 전까지는 모든 기능이 뛰어납니다. 지금까지 우리는 검색 결과에 0, 또는 0을 반환한다고 계산했습니다. 오류가 없으며 결과가 없습니다.

특정 단어가 검색 쿼리에서 제외되도록 "블랙리스트"하는 방법입니다.

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(); 
} 

문제는 우리가 문제를 일으키는 것으로 보이는 또 다른 "키워드"를 발견했다는 것입니다. "Do"는 결과가 돌아 오지 않게합니다. 나는 단지 그것을 블랙리스트에 보낼 수 있지만,이 일이 커짐에 따라 이것을 처리하는 잘못된 길로 느껴지기 시작했다.

더 나은 방법이 있나요?

는 편집 : 나는 단어를 검색, 모든 검색 문자열을 마사지하지 않으면

몇 가지 다른 시나리오는

"없습니다" "널 또는 빈 전체 텍스트 조건 자."오류가 발생합니다

동일한 문자열을 그대로 적용하면 회사를 "회사에서 삭제하지 않음"으로 설정하면 Do 또는 Not가있는 문자열의 버전이 모두 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; 
} 
관련 문제