как разбить поисковый запрос - PullRequest
1 голос
/ 27 марта 2012

Я разрабатываю поисковую систему для CCG. Я хочу, чтобы пользователь мог находить карточки по запросу типа "blue brigade hero enhancements that can discard ec's" или "purple kings of israel". Есть много переменных для поиска: бригады (фиолетовые, синие), типы (герои, злые персонажи [ес]), специальные способности (сброс) и идентификаторы (короли Израиля). Я думаю о регулярных выражениях, чтобы найти общие параметры поиска. Я знаю, что это будет нелегко, и на настройку уйдет много времени, но может ли кто-нибудь указать мне правильное направление? Является ли регулярное выражение даже рекомендуемым решением? Я не знаю, важно ли это, но я использую php и mysql.

Ответы [ 3 ]

7 голосов
/ 29 марта 2012

Вам потребуется написать анализатор для разбора таких строк запроса.

Регулярные выражения будут полезны для поиска «глаголов» и «существительных» в строках запроса, но вам, вероятно, также понадобится неконтекстная грамматика, описывающая язык ваших запросов, например что-то вроде этого:

<QUERY> := <TARGET_SPEC>
<TARGET_SPEC> := <OBJECT> 'that can' <ABILITY>
<TARGET_SPEC> := <OBJECT>  
<OBJECT> := <COLOR> <WHAT> 
<OBJECT> := <WHAT>
<COLOR> := 'blue' | 'red' | 'purple' | 'green' 
<WHAT> := <ITEM> | <HERO>
<ITEM> := <ADJECTIVE> <ITEM>
<ADJECTIVE> := 'brigade' | 'hero' | 'magic' | 'enhanced' | 'rustproof'
<ITEM> := 'enhancements' | 'sword' | 'potion'
<HERO> := <HERO> 'of' <COUNTRY>
<HERO> := 'kings' | 'knights' | 'thiefs'
<COUNTRY> := 'israel' | 'palestine' | 'jordan' | 'egypt'
<ABILITY> := <ABILITY> 'and' <ABILITY>
<ABILITY> := 'swim' | 'dance' | discard <DISCARDABLE> | 'kill' <HERO> | 'use' <ITEM>
<DISCARDABLE> := 'ec's' | 'et's' | 'etc'

Парсер, построенный на основе такой грамматики, сможет определить, какая часть вашего запроса является объектом, который является способностью, цветом, страной и т. Д. Например, для заданной входной строки «красные рыцари Иордана, которые могутswim ', парсер выберет правильные правила и применит их:

<QUERY> := 'red knights of jordan that can swim'
<TARGET_SPEC> := 'red knights of jordan that can swim'
<TARGET_SPEC> := 'red knights of jordan' 'that can' 'swim'
<OBJECT> := 'red knights of jordan'
<ABILITY> := 'swim'
<COLOR> := 'red'
<WHAT> := 'knights of jordan'
<HERO> := 'knights' 'of' 'jordan'
<HERO> := 'knights'
<COUNTRY> := 'jordan'

На основе извлеченной информации вы сможете создавать критерии поиска.

Использование грамматики имеет дополнительное преимущество, заключающееся в устранении некоторых двусмысленностей, которые было бы трудно разрешить любым другим способом - например, если пользователь запрашивает «красных королей, которые могут убить белых рыцарей», простые алгоритмы, которые просто ищутсопоставить каждое слово со списком доступных цветов не удастся.

Рекомендую прочитать книгу о дизайне компилятора - Книга Дракона - классический выбор (вам не нужно читать всеэто просто часть о лексерах и парсерах).

Если вы не хотите кодировать весь синтаксический анализатор самостоятельно (поскольку это может быть довольно трудоемким и подверженным ошибкам), вам потребуется генератор синтаксического анализатора (то есть программа, которая создает исходный код синтаксического анализатора).код для данной грамматики); здесь - это вопрос с некоторыми предложениями по PHP.

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

0 голосов
/ 29 марта 2012

С TierTempCur As

--/*Use Rela table to get the offspring of the parent*/ 

        (
            SELECT Rela.ID_RSSD_PARENT
                , Rela.ID_RSSD_OFFSPRING
                , '12/31/2011' AS REPORT_DATE
                , 1 As TREE_LVL 
                , CHECKSUM(ID_RSSD_PARENT, ID_RSSD_OFFSPRING) As CHKSUM 
                , RIGHT('000000000'+ CONVERT(VARCHAR(MAX),ID_RSSD_OFFSPRING),9) AS RSSD_PATH 
            FROM CUV_RELATIONSHIPS As Rela
            WHERE ID_RSSD_PARENT = 451965 AND '12/31/2011' BETWEEN D_DT_START AND D_DT_END 
                AND Rela.CTRL_IND = 1      --/* indicates subsidiary */
                AND Rela.OTHER_BASIS_IND not in (3,8)  --/* Per DM's job */

            UNION ALL

            SELECT Rela.ID_RSSD_PARENT
                , Rela.ID_RSSD_OFFSPRING
                , REPORT_DATE
                , TREE_LVL + 1 As TREE_LVL
                , CHECKSUM(Rela.ID_RSSD_PARENT, Rela.ID_RSSD_OFFSPRING) As CHKSUM 
                , Tmp.RSSD_PATH + '\' + RIGHT('000000000'+ CONVERT(VARCHAR(MAX),Rela.ID_RSSD_OFFSPRING),9) AS RSSD_PATH 
            FROM CUV_RELATIONSHIPS As Rela
            INNER JOIN TierTempCur As Tmp 
              ON Rela.ID_RSSD_PARENT = Tmp.ID_RSSD_OFFSPRING
              AND REPORT_DATE BETWEEN Rela.D_DT_START AND Rela.D_DT_END
            WHERE TREE_LVL < 20          --/*max depth for the tier is 20 -- to end self referencing parent/child relationships */
              AND Rela.CTRL_IND = 1      --/* indicates subsidiary */
              AND Rela.OTHER_BASIS_IND not in (3,8)
        ),
0 голосов
/ 29 марта 2012

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

Если у вас есть словарь известных поисковых терминов и возможность исправить их для синтаксиса и грамматики (подсказка: используйте вашу базу данных и OED в качестве слоя кеша, выбрасывая любые ошибки кеша в Google), вы может выполнять поиск путем двоичной сортировки сегментов каждого термина по наборам известных типов. Используя ваш пример, каждый сегмент будет: brigade_purple, brigade_blue, type_hero, type_evil, каждая из ваших специальных способностей и каждый из ваших специальных идентификаторов типов.

Для каждой карты создайте битовое поле, соответствующее вашим сегментам. Для каждого пользовательского запроса создайте то же самое. Затем верните результаты, соответствующие вашей битовой маске, выполнив побитовый обход базы данных, который, как я предполагаю, для этого игрушечного примера будет иметь форму B + дерево , сортируя результаты, наиболее близкие к маске в мажоре порядок Преимущество этого заключается в возможности расширения до максимальной длины вашего резервного битового поля, которое может быть практически неограниченным во многих реализациях базы данных.

Хорошо, это немного технически. В любом случае, я бы построил поисковую базу данных.

...