Использование полнотекстового поиска в SQL Server 2008 по нескольким таблицам и столбцам
-
03-07-2019 - |
Вопрос
Мне нужно выполнить поиск по нескольким столбцам из двух таблиц в моей базе данных, используя полнотекстовый поиск.В двух рассматриваемых таблицах соответствующие столбцы проиндексированы полнотекстово.
Причина, по которой я выбираю полнотекстовый поиск:1.Чтобы иметь возможность легко искать слова акцентированных слов (Cafè) 2.Уметь ранжировать по близости слов и т. д.3."Вы имели в виду ххх?" функциональность
Вот дурачок структура таблицы, чтобы проиллюстрировать задачу:
Настольная книга BookID Name (Full-text indexed) Notes (Full-text indexed) Настольная полка ShelfID BookID Стол ПолкаАвтор AuthorID ShelfID Таблица Автор AuthorID Name (Full-text indexed)
Мне нужно выполнить поиск по названию книги, примечаниям к книге и имени автора.
Я знаю два способа добиться этого:
Использование полнотекстового индексированного представления: Это был бы мой предпочтительный метод, но я не могу этого сделать, потому что для полнотекстовой индексации представления оно должно быть привязано к схеме, не иметь каких-либо внешних соединений и иметь уникальный индекс.Представление, которое мне понадобится для получения данных, не удовлетворяет этим ограничениям (оно содержит множество других объединенных таблиц, из которых мне нужно получить данные).
Использование объединений в хранимой процедуре:Проблема этого подхода в том, что мне нужно отсортировать результаты по рангу.Если я делаю несколько объединений между таблицами, SQL Server по умолчанию не будет выполнять поиск по нескольким полям.Я могу объединить два отдельных запроса CONTAINS к двум связанным таблицам, но не знаю, как извлечь комбинированный ранжирование по двум поисковым запросам.Например, если я ищу «Артур», результаты запроса «Книга» и «Автор» должны быть приняты во внимание и соответствующим образом взвешены.
Решение
Используя FREETEXTTABLE, вам просто нужно разработать некоторый алгоритм для расчета объединенного ранга для каждого результата объединенной таблицы.В приведенном ниже примере результат искажается в сторону совпадений из таблицы book.
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
Обратите внимание, что я упростил вашу схему для этого примера.
Другие советы
У меня была та же проблема, что и у вас, но на самом деле в ней участвовало 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
Это оказалось невероятно быстрее.
Я надеюсь, что это помогает.
Я не думаю, что принятый ответ решит проблему.Если вы попытаетесь найти все книги определенного автора и, следовательно, будете использовать имя автора (или его часть) в качестве критерия поиска, единственными книгами, возвращаемыми по запросу, будут те, критерии поиска которых указаны в его собственном имени. .
Единственный способ, которым я вижу эту проблему, — это реплицировать столбцы автора, по которым вы хотите выполнять поиск, в таблице книги и индексировать эти столбцы (или столбец, поскольку, вероятно, было бы разумно хранить соответствующую информацию об авторе в столбце XML в книге). стол).
Кстати, в аналогичной ситуации наш администратор базы данных создал триггеры DML для поддержки специальной таблицы полнотекстового поиска.Использовать материализованное представление было невозможно из-за его многочисленных ограничений.
Я бы использовал хранимую процедуру.Полнотекстовый метод или что-то еще возвращает ранг, по которому вы можете сортировать.Я не уверен, как они будут соотноситься друг с другом, но я уверен, что вы могли бы немного повозиться и во всем разобраться.Например:
Select SearchResults.key, SearchResults.rank From FREETEXTTABLE(myColumn, *, @searchString) as SearchResults Order By SearchResults.rank Desc
Этот ответ уже давно назрел, но один из способов сделать это, если вы не можете изменить основные таблицы, — это создать новую таблицу с добавленными в один столбец параметрами поиска.
Затем создайте полнотекстовый индекс для этого столбца и запросите этот столбец.
Пример
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 — это новая таблица и столбец с добавленными полями. Теперь вы можете выполнить запрос к новой таблице с объединениями с таблицей, из которой вы хотите отобразить данные. .
Надеюсь это поможет