Использование полнотекстового поиска в SQL Server 2008 по нескольким таблицам, столбцам - PullRequest
16 голосов
/ 31 декабря 2008

Мне нужно искать по нескольким столбцам из двух таблиц в моей базе данных, используя полнотекстовый поиск. Обе таблицы имеют соответствующие полнотекстовые индексированные столбцы.

Причина, по которой я выбираю полнотекстовый поиск: 1. Чтобы можно было легко найти акцентированные слова (кафе) 2. Чтобы иметь возможность ранжироваться в соответствии с близостью слова и т. Д. 3. «Вы имели в виду XXX?» функциональность

Вот пустышка структура таблицы, чтобы проиллюстрировать проблему:

<strong>Table Book</strong>
BookID
Name (Full-text indexed)
Notes (Full-text indexed)

<strong>Table Shelf</strong>
ShelfID
BookID

<strong>Table ShelfAuthor</strong>
AuthorID
ShelfID

<strong>Table Author</strong>
AuthorID
Name (Full-text indexed)

Мне нужно выполнить поиск по названию книги, заметкам и имени автора.

Я знаю два способа сделать это:

  1. Использование полнотекстового индексированного представления: Это был бы мой предпочтительный метод, но я не могу этого сделать, потому что для представления, который будет полнотекстовым индексировать, он должен быть привязанные к схеме, не имеют внешних соединений, имеют уникальный индекс. Представление, которое мне понадобится для получения моих данных, не удовлетворяет этим ограничениям (оно содержит много других объединенных таблиц, из которых мне нужно получать данные).

  2. Использование объединений в хранимой процедуре : проблема этого подхода в том, что мне нужно отсортировать результаты по рангу. Если я делаю несколько объединений по таблицам, SQL Server не будет выполнять поиск по нескольким полям по умолчанию. Я могу объединить два отдельных запроса CONTAINS для двух связанных таблиц, но я не знаю, как извлечь объединенный ранг из двух поисковых запросов. Например, если я ищу «Артур», результаты как запроса «Книга», так и запроса «Автор» должны быть приняты во внимание и соответственно взвешены.

Ответы [ 6 ]

15 голосов
/ 31 декабря 2008

Используя FREETEXTTABLE, вам просто нужно разработать алгоритм для вычисления ранга слияния для каждого результата объединенной таблицы. В приведенном ниже примере результат смещается в сторону попаданий из таблицы книг.

SELECT b.Name, a.Name, bkt.[Rank] + akt.[Rank]/2 AS [Rank]
FROM Book b
INNER JOIN Author a ON b.AuthorID = a.AuthorID
INNER JOIN FREETEXTTABLE(Book, Name, @criteria) bkt ON b.ContentID = bkt.[Key] 
LEFT JOIN FREETEXTTABLE(Author, Name, @criteria) akt ON a.AuthorID = akt.[Key]
ORDER BY [Rank] DESC

Обратите внимание, что я упростил вашу схему для этого примера.

5 голосов
/ 08 августа 2016

У меня была та же проблема, что и у вас, но на самом деле она включала 10 таблиц (таблица пользователей и несколько других для информации)

Я выполнил первый запрос, используя FREETEXT в предложении WHERE для каждой таблицы, но запрос занимал слишком много времени.

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

Я исправил это, используя комбинацию FREETEXTTABLE и UNION:

SELECT Users.* FROM Users INNER JOIN
(SELECT Users.UserId FROM Users INNER JOIN FREETEXTTABLE(Users, (column1, column2), @variableWithSearchTerm) UsersFT ON Users.UserId = UsersFT.key
UNION
SELECT Table1.UserId FROM Table1 INNER JOIN FREETEXTTABLE(Table1, TextColumn, @variableWithSearchTerm) Table1FT ON Table1.UserId = Table1FT.key
UNION
SELECT Table2.UserId FROM Table2 INNER JOIN FREETEXTTABLE(Table2, TextColumn, @variableWithSearchTerm) Table2FT ON Table2.UserId = Table2FT.key
... --same for all tables
) fts ON Users.UserId = fts.UserId

Это оказалось невероятно намного быстрее.

Надеюсь, это поможет.

3 голосов
/ 27 августа 2009

Не думаю, что принятый ответ решит проблему. Если вы пытаетесь найти все книги определенного автора и, следовательно, используете имя автора (или его часть) в качестве критерия поиска, единственными книгами, возвращаемыми запросом, будут те, которые имеют критерии поиска от своего собственного имени. .

Единственный способ обойти эту проблему - это реплицировать столбцы автора, по которым вы хотите выполнить поиск, в таблице книг и индексировать эти столбцы (или столбцы, поскольку, вероятно, было бы разумно хранить соответствующую информацию автора в столбце XML). в таблице книги).

2 голосов
/ 19 февраля 2011

FWIW, в аналогичной ситуации наш администратор баз данных создал триггеры DML для ведения выделенной таблицы полнотекстового поиска. Было невозможно использовать материализованное представление из-за его многочисленных ограничений.

1 голос
/ 31 декабря 2008

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

Select SearchResults.key, SearchResults.rank From FREETEXTTABLE(myColumn, *, @searchString) as SearchResults Order By SearchResults.rank Desc
0 голосов
/ 31 декабря 2016

Этот ответ давно просрочен, но один из способов сделать это, если вы не можете изменить первичные таблицы, - создать новую таблицу с параметрами поиска, добавленными в один столбец.

Затем создайте полнотекстовый индекс для этого столбца и выполните запрос к этому столбцу.

Пример

SELECT 
    FT_TBL.[EANHotelID]                 AS HotelID, 
    ISNULL(FT_TBL.[Name],'-')           AS HotelName,
    ISNULL(FT_TBL.[Address1],'-')       AS HotelAddress,
    ISNULL(FT_TBL.[City],'-')           AS HotelCity,
    ISNULL(FT_TBL.[StateProvince],'-')  AS HotelCountyState,
    ISNULL(FT_TBL.[PostalCode],'-')     AS HotelPostZipCode,
    ISNULL(FT_TBL.[Latitude],0.00)      AS HotelLatitude,
    ISNULL(FT_TBL.[Longitude],0.00)     AS HotelLongitude,
    ISNULL(FT_TBL.[CheckInTime],'-')    AS HotelCheckinTime,
    ISNULL(FT_TBL.[CheckOutTime],'-')   AS HotelCheckOutTime,
    ISNULL(b.[CountryName],'-')         AS HotelCountry,
    ISNULL(c.PropertyDescription,'-')   AS HotelDescription,
    KEY_TBL.RANK 

    FROM [EAN].[dbo].[tblactivepropertylist] AS FT_TBL INNER JOIN
     CONTAINSTABLE ([EAN].[dbo].[tblEanFullTextSearch], FullTextSearchColumn, @s)
      AS KEY_TBL
    ON FT_TBL.EANHotelID = KEY_TBL.[KEY]
    INNER JOIN [EAN].[dbo].[tblCountrylist] b
    ON FT_TBL.Country = b.CountryCode
    INNER JOIN [EAN].[dbo].[tblPropertyDescriptionList] c
    ON FT_TBL.[EANHotelID] = c.EANHotelID

В приведенном выше коде [EAN]. [Dbo]. [TblEanFullTextSearch], FullTextSearchColumn - это новая таблица и столбец с добавленными полями, теперь вы можете выполнить запрос к новой таблице с присоединениями к таблице, которую вы хотите отобразить данные из.

Надеюсь, это поможет

...