Хранимая процедура T-SQL для возврата «предложенных» результатов поиска в стиле Google - PullRequest
7 голосов
/ 23 декабря 2010

Хорошо, с использованием SQL Server 2008. На моей веб-странице есть текстовое поле с подключенным автозаполнением jQuery-UI.

Теперь мне нужна хранимая процедура для поиска по всем столбцам одной таблицы (или несколькихя полагаю, что это соединенные таблицы) для строки поиска, поступающей из AJAX-вызова textbox / autocomplete, и возвращающей «предложенные» строки поиска.Я использую базу данных AdventureWorks для тестирования (Таблица продуктов)

Так, например, в таблице продуктов есть столбцы для названия продукта и номера продукта (среди прочих), и я хочу вернуть предлагаемые строки поиска на основе ввода пользователя, гдеони могут ввести название продукта и / или номер продукта.

У меня это работает через один столбец, который был простым.Есть идеи?

Ответы [ 4 ]

6 голосов
/ 23 декабря 2010

Я собираюсь предложить полнотекстовый поиск (MS 'или Lucene будет работать). Приведенный ниже код использует MSSQL FTS как то, что я использую в своем приложении в настоящий момент.

Установите FTS Search, если у вас естьужеЕсли у вас есть проверка службы запущена.В Management Studio запустите это, чтобы настроить каталог и добавить таблицу продуктов;и Цвет / Имя / Номер продукта в каталоге.

USE [AdventureWorks]
GO
CREATE FULLTEXT CATALOG [ProductsTest]WITH ACCENT_SENSITIVITY = OFF
AUTHORIZATION [dbo]

GO

USE [AdventureWorks]
GO
CREATE FULLTEXT INDEX ON [Production].[Product] KEY INDEX [PK_Product_ProductID] ON ([ProductsTest]) WITH (CHANGE_TRACKING AUTO)
GO
USE [AdventureWorks]
GO
ALTER FULLTEXT INDEX ON [Production].[Product] ADD ([Color])
GO
USE [AdventureWorks]
GO
ALTER FULLTEXT INDEX ON [Production].[Product] ADD ([Name])
GO
USE [AdventureWorks]
GO
ALTER FULLTEXT INDEX ON [Production].[Product] ADD ([ProductNumber])
GO
USE [AdventureWorks]
GO
ALTER FULLTEXT INDEX ON [Production].[Product] ENABLE
GO

Затем можно выполнить запросы ко всем столбцам одновременно;например, серебро (выбрано в качестве цвета и имени)

Select * from production.product where
contains(*, '"Silver*"')

* в запросе будет найдено серебро *, так что вы можете использовать его для получения результатов при вводе пользователем. Следует учитывать, чтоGoogle делает эту работу в режиме реального времени - если вы ищете много данных, вы сможете получить данные обратно, не прерывая набор текста пользователя.я думаю, что обычно люди используют эти поиски, набирая их с первой буквы - я принимаю, что будут орфографические ошибки - вы могли бы реализовать проверку орфографии после каждого пробела, который они нажимают, возможно, чтобы справиться с этим.Или сохраните выполненные поиски, посмотрите на неправильные написания и измените код для обработки этого на основе сопоставления (или в FTS с использованием пользовательского тезауруса.)

Ранжирование будет интересной проблемой для любого разработчика.бизнес;Вы находите первый результат для Mountain Frame - или вы хотите оценить их по продажам или цене?Если пользователь вводит более одного текстового термина, вы можете использовать FTS для составления рейтинга на основе строки поиска.

select aa.rank, bb.* 
From containstable(production.product, *, '"Mountain" and "Silver*"') aa
inner join production.product bb
on aa.[key] = bb.productid
order by rank desc

Возвращает 30 строк;и весовые коэффициенты на основе введенного пользователем текста для определения первой записи места.В любом случае вы, вероятно, захотите добавить закодированное ранжирование, чтобы настроить результаты в соответствии с вашими бизнес-желаниями - ранжирование виджета 1 с наивысшей ценой 1 может оказаться не лучшим решением.Вот почему вы собираетесь хранить то, что люди искали / нажимали, чтобы вы могли проанализировать результаты позже.

Существует действительно хороший анализатор языка для .Net, который переводит стиль Google.Строковый запрос, введенный на языке FTS'able, который дает знакомство с любыми логическими поисками, которые используют ваш сайт.

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

В качестве окончательного предложения, если это коммерческий веб-сайт, вы можете посмотреть Easyask , который пугаетотличный процессор естественного языка

3 голосов
/ 23 декабря 2010

Использование функции soundex было бы самым простым способом сопоставления похожих «элементов» в нескольких столбцах.Но лучший алгоритм сопоставления, который будет реализован почти так же быстро, это Расстояние Левенштейна для редактирования .Вот реализация T-SQL , заключенная в функцию.Используйте его для сопоставления с похожими условиями поиска.

EDIT Образец Левенштиена в действии (на основе SQL-кода gbn)

Предположим, вы назвали свою функцию Левенштейна T-SQL lvn (просто ради краткости) тогда вы можете сделать что-то вроде:

SELECT productname FROM foo WHERE productname 
    LIKE '%myinput%' OR lvn(myinput) < 3
UNION
SELECT productnumber FROM foo WHERE productnumber 
    LIKE '%myinput%' OR lvn(myinput) < 3
UNION
...

ORDER BY 1 -- one-based column index sort for UNION queries

Да.так просто.Кстати, я обновил ссылку Левенштейна T-SQL на что-то, что имеет больше смысла, и это принятый SO ответ.

2 голосов
/ 23 декабря 2010

Редактировать: использовать UNION для объединения отдельных запросов

SELECT productname FROM foo WHERE productname LIKE '%myinput%'
UNION
SELECT productnumber FROM foo WHERE productnumber LIKE '%myinput%'
UNION
...

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

0 голосов
/ 23 июня 2016

Я создал образец SQL, который будет возвращать результаты поиска в стиле Google. Вы можете попробовать этот T-SQL. Вы также можете добавить более одного критерия поиска по столбцу таблицы.

ALTER PROC [dbo].[USP_GetDoctorLookupList]
(
    @SearchText varchar(50),
    @ItemCount int
)
AS
BEGIN
    SET @SearchText = RTRIM(@SearchText) + '%'
    BEGIN
        SELECT TOP (@ItemCount) * 
        FROM
        (
            SELECT
                CASE 
                    WHEN RTRIM(LTRIM(d.cdocname)) LIKE @SearchText then 1 
                    WHEN RTRIM(LTRIM(d.cdeano)) LIKE @SearchText then 2 

                END OrderBy,
                d.docid_PK,
                d.cdocname,
                d.cdeano

            FROM doctor d

            WHERE 
                (d.cdocname LIKE @SearchText
                OR d.cdeano LIKE @SearchText
                )  
        ) Doc ORDER BY OrderBy, cdocname
    END
END
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...