Назад | Перейти на главную страницу

Как мне изменить тезаурус для полнотекстовой индексации в 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. Я ожидал бы того же количества результатов, поэтому я предполагаю, что сервер на самом деле не обновляет тезаурус.

Любые идеи?

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

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

Это функция 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 позже, я всегда могу попробовать его функциональность тезауруса, поскольку я считаю, что это лучше. А пока это будет работать.