Как изменить тезаурус для полнотекстовой индексации в SQL 2005?

Итак, я прочитал это: http://www.simple-talk.com/sql/learn-sql-server/understanding-full-text-indexing-in-sql-server/

И я сделал следующую модификацию файла tsENU.xml, включив синонимы "программист" и "программирование":

<XML ID="Microsoft Search Thesaurus">
    <thesaurus xmlns="x-schema:tsSchema.xml">
        <diacritics_sensitive>0</diacritics_sensitive>
        <expansion>
            <sub>Internet Explorer</sub>
            <sub>IE</sub>
            <sub>IE5</sub>
        </expansion>
        <replacement>
            <pat>NT5</pat>
            <pat>W2K</pat>
            <sub>Windows 2000</sub>
        </replacement>
        <expansion>
            <sub>run</sub>
            <sub>jog</sub>
        </expansion>
        <expansion>
            <sub>programmer</sub>
            <sub>programming</sub>
        </expansion>
    </thesaurus>
</XML>

И в качестве последнего шага я перезапустил службу полнотекстового индексирования.

Все, что я прочитал, указывает на то, что это все, что мне нужно сделать. Но, увы, это не влияет на результаты поиска, как я ожидаю. Поиск "программирования" в моей базе данных возвращает 59 результатов, в то время как "программист" возвращает только 1. Я ожидаю того же числа результатов, поэтому я предполагаю, что сервер фактически не обновляет тезаурус.

Есть идеи?

1 ответ

Решение

Поэтому я отказался от этой проблемы с сервером и решил ее с помощью кода.

Это не моя идея идеального решения, но я создал свой тезаурус примерно за час. И это меньше времени, чем я потратил на исследование этого предмета.

Это функция VB.NET, которую я написал:

  Public Shared Function GetFullTextSearch(ByVal strSearch As String) As String
    If strSearch > "" Then
      strSearch = Regex.Replace(strSearch, "\s\s+", " ").Trim.ToLower
      strSearch = Regex.Replace(strSearch, "[^\w\s]", "")

      Dim arrKeywords() As String = strSearch.Split(" ")
      Dim strFullTextSearch As String = ""

      Dim xpathDoc As XPathDocument
      Dim xmlNav As XPathNavigator
      Dim xmlNI As XPathNodeIterator

      Try
        xpathDoc = New XPathDocument(Current.Server.MapPath("~\bin\FullTextSynonyms.xml"))
        xmlNav = xpathDoc.CreateNavigator()
      Catch ex As Exception
        Current.Trace.Warn(ex.ToString)
      End Try

      For Each strKeyword As String In arrKeywords
        If strFullTextSearch > "" Then
          strFullTextSearch &= " AND "
        End If

        If Not xpathDoc Is Nothing Then
          xmlNI = xmlNav.Select("/Thesaurus/Synonyms[Synonym='" & strKeyword & "']/Synonym")
          If xmlNI.Count > 0 Then
            Dim strSearchOr As String = ""
            While xmlNI.MoveNext()
              If strSearchOr > "" Then
                strSearchOr &= " OR "
              End If
              strSearchOr &= "FORMSOF(INFLECTIONAL, '" & xmlNI.Current.Value & "')"
            End While

            If strSearchOr > "" Then
              strFullTextSearch &= "(" & strSearchOr & ")"
            End If
          Else
            strFullTextSearch &= "FORMSOF(INFLECTIONAL, '" & strKeyword & "')"
          End If
        End If
      Next

      Return strFullTextSearch
    Else
      Return Nothing
    End If
  End Function

И соответствующий файл пользовательского тезауруса:

<?xml version="1.0" encoding="utf-8" ?> 
<Thesaurus>
    <Synonyms>
        <Synonym>program</Synonym>
        <Synonym>programmer</Synonym>
        <Synonym>programming</Synonym>
    </Synonyms>
    <Synonyms>
        <Synonym>consult</Synonym>
        <Synonym>consultant</Synonym>
        <Synonym>consulting</Synonym>
    </Synonyms>
    <Synonyms>
        <Synonym>web</Synonym>
        <Synonym>website</Synonym>
    </Synonyms>
</Thesaurus>

По сути, это создает немного больше обработки, чем может потребоваться, поскольку в некоторых случаях я использую функцию FORMSOF несколько раз на похожих условиях.

Например, когда пользователь ищет "веб-консультант", это фактический полнотекстовый поиск, который передается в функцию CONTAINSTABLE:

(FORMSOF(INFLECTIONAL, 'web') OR FORMSOF(INFLECTIONAL, 'website')) AND (FORMSOF(INFLECTIONAL, 'consult') OR FORMSOF(INFLECTIONAL, 'consultant') OR FORMSOF(INFLECTIONAL, 'consulting'))

Конечно, это не самое эффективное решение, но оно все еще очень быстро работает с нашей базой данных и функционально это то, что я искал. Кроме того, теперь у меня есть возможность изменять мой пользовательский файл тезауруса без необходимости перезапуска службы полнотекстовой индексации. Но, эй, если мы обновимся до SQL 2008 позже, я всегда могу попробовать его функциональность тезауруса, так как считаю, что это лучше. До тех пор, это будет работать.

Другие вопросы по тегам