Полнотекстовый поиск SQL Server 2005 по нескольким таблицам и столбцам - PullRequest
3 голосов
/ 13 января 2010

Я ищу хорошее решение для эффективного использования функции «Содержимое таблицы» в SQL Serve r2005. В настоящее время у меня есть, например, Сотрудник и таблица адресов.

-Employee
Id
Name

-Address
Id
Street
City
EmployeeId

Теперь пользователь может вводить поисковые термины только в одно текстовое поле, и я хочу, чтобы эти термины разделялись и выполнялись с помощью оператора «И». FREETEXTTABLE, кажется, работает с "ИЛИ" автоматически.

Теперь допустим, что пользователь ввел «Джон Гамбург». Это значит, что он хочет найти Джона в Гамбурге. Так что это "Джон И Гамбург".

Таким образом, следующее не будет содержать результатов, так как CONTAINSTABLE проверяет каждый столбец на наличие "John AND Hamburg".

Итак, мой вопрос: каков наилучший способ выполнения полнотекстового поиска с операторами AND по нескольким столбцам / таблицам?

SELECT *
FROM Employee emp
    INNER JOIN 
        CONTAINSTABLE(Employee, *, '(JOHN  AND Hamburg)', 1000) AS keyTblSp
        ON sp.ServiceProviderId = keyTblSp.[KEY]    
    LEFT OUTER JOIN [Address] addr ON addr.EmployeeId = emp.EmployeeId
UNION ALL
SELECT *
FROM Employee emp 
    LEFT OUTER JOIN [Address] addr ON addr.EmployeeId = emp.EmployeeId
    INNER JOIN 
        CONTAINSTABLE([Address], *, '(JOHN  AND Hamburg)', 1000) AS keyTblAddr
        ON addr.AddressId = keyTblAddr.[KEY]    

...

Ответы [ 2 ]

6 голосов
/ 13 января 2010

Это скорее проблема синтаксиса. Как вы угадаете намерение пользователя с помощью всего одного поля ввода?

  • Они ищут "Джона Гамбурга" человека?
  • Они ищут "улицу Джона Гамбурга"?
  • Они ищут "Джона", который живет на "Гамбург-стрит" в Спрингфилде?
  • Они ищут "Джона", который живет в городе "Гамбург"?

Не зная намерений пользователя, лучшее, на что вы можете надеяться, - это ИЛИ условия и получение попаданий с самым высоким рейтингом.

В противном случае вам нужно запрограммировать тонну логики, в зависимости от количества слов, переданных в:

2 слова:

Поиск данных сотрудника для термина 1, Поиск данных сотрудника для термина 2, Поиск данных адреса для термина 1, Поиск данных адреса для термина 2. Слияние результатов по термину, порядок по большинству обращений.

3 слова:

Поиск данных сотрудника для термина 1, Поиск данных сотрудника для термина 2, Поиск данных сотрудника для термина 3, Поиск данных адреса для термина 1, Поиск данных адреса для термина 2, Поиск данных адреса для термина 3. Объединение результатов по термину, порядок по большинству хитов.

и т.д ...

Полагаю, я бы перепроектировал графический интерфейс, чтобы разделить ввод как минимум на Имя и Адрес. Если это невозможно, примените правило синтаксиса: «Первые слова будут считаться именем до появления запятой, любые слова после этого будут считаться адресами»

EDIT:

Ваша лучшая ставка по-прежнему - ИЛИ условия, и берите хиты с самым высоким рейтингом. Вот пример этого и пример, почему это не идеально без какой-либо предварительной обработки ввода для определения намерений пользователя:

insert into Employee (id, [name]) values (1, 'John Hamburg')
insert into Employee (id, [name]) values (2, 'John Smith')
insert into Employee (id, [name]) values (3, 'Bob Hamburg')
insert into Employee (id, [name]) values (4, 'Bob Smith')
insert into Employee (id, [name]) values (5, 'John Doe')

insert into Address (id, street, city, employeeid) values (1, 'Main St.', 'Springville', 1)
insert into Address (id, street, city, employeeid) values (2, 'Hamburg St.', 'Springville', 2)
insert into Address (id, street, city, employeeid) values (3, 'St. John Ave.', 'Springville', 3)
insert into Address (id, street, city, employeeid) values (4, '5th Ave.', 'Hamburg', 4)
insert into Address (id, street, city, employeeid) values (5, 'Oak Lane', 'Hamburg', 5)

Теперь, поскольку мы не знаем, какие ключевые слова будут применяться к какой таблице, мы должны предположить, что они могут применяться к любой из этих таблиц, поэтому нам нужно ИЛИ условия для каждой таблицы, ОБЪЕДИНИТЬ результаты, агрегировать их и вычислить высший ранг.

SELECT Id, [Name], Street, City, SUM([Rank])
FROM
(
    SELECT emp.Id, [Name], Street, City, [Rank]
    FROM Employee emp 
    JOIN [Address] addr ON emp.Id = addr.EmployeeId
    JOIN CONTAINSTABLE(Employee, *, 'JOHN OR Hamburg') AS keyTblEmp ON emp.Id = keyTblEmp.[KEY]

    UNION ALL

    SELECT emp.Id, [Name], Street, City, [Rank]
    FROM Employee emp 
    JOIN [Address] addr ON emp.Id = addr.EmployeeId
    JOIN CONTAINSTABLE([Address], *, 'JOHN OR Hamburg') AS keyTblAdd ON addr.Id = keyTblAdd.[KEY]   
) as tmp

GROUP BY Id, [Name], Street, City
ORDER BY SUM([Rank]) DESC

Это не идеально, вот что вы получите для примера (в вашем случае вы бы хотели, чтобы Джон Доу из Гамбурга появился первым):

Id       Name              Street            City           Rank
2        John Smith        Hamburg St.       Springville    112
3        Bob Hamburg       St. John Ave.     Springville    112
5        John Doe          Oak Lane          Hamburg        96
1        John Hamburg      Main St.          Springville    48
4        Bob Smith         5th Ave.          Hamburg        48

Но это лучшее, что вы можете сделать, не анализируя входные данные, прежде чем отправлять их в SQL, чтобы сделать "наилучшее предположение" о том, что хочет пользователь.

2 голосов
/ 07 декабря 2011

У меня была такая же проблема. Вот мое решение, которое сработало для моего случая:

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

SELECT emp.*, addr.*, ISNULL(emp.Name,'') + ' ' + ISNULL(addr.City, '') AS SearchResult 
FROM Employee emp 
    LEFT OUTER JOIN [Address] addr ON addr.EmployeeId = emp.EmployeeId

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

SELECT *
FROM vEmpAddr ea
INNER JOIN CONTAINSTABLE(vEmpAddr, *, 'John AND Hamburg') a ON ea.ID = a.[Key]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...