Шаблон проектирования для развернутого / отфильтрованного поиска

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

http://www.newegg.com/Product/ProductList.aspx?Submit=ENE&N=2010150014%201035507776&name=7200%20RPM

Я работаю с различными объектами, похожими на продукты, которые имеют разные критерии. Кто-нибудь может порекомендовать хороший дизайн для создания поисковой системы, как NewEgg's?

2 ответа

Решение

Хранение данных "по вертикали", т. Е. В формате Entity-Attribute-Value (EAV), наряду с управлением схемами [meta], управляемыми данными, неявными для EAV, обеспечивают структуру, в которой атрибуты каждого продукта "независимы" друг от друга. Это, в свою очередь, облегчает реализацию детализации (т. Е. Управляемого уточнения запроса, когда на каждом этапе конечному пользователю предоставляется список возможных атрибутов, все еще применимых, для каждого такого атрибута список возможных значений).

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

Изменить: более подробно / ресурсы на EAV
По общему признанию, статья Wikipedia об этом несколько абстрактна...
В двух словах, модель определяет следующие понятия:

  • Сущность (иначе говоря, продукт или предмет) = "запись" в традиционном реляционном жаргоне
  • Атрибут = "столбец" (он же "поле") в языке РСУБД
  • Значение = числовое (или строковое или иное) значение данного столбца для данной записи.
  • Тип (он же категория) = [свободно] "таблица" в СУБД, т. Е. Набор записей, которые, как правило, имеют один и тот же набор атрибутов.

Чтобы проиллюстрировать это, скажем, каталогом товаров для электроники, объектом может быть конкретный "Монитор с плоским экраном", его типом может быть "Устройства отображения", его атрибуты "Размер", "Разрешение", "Цена" и т. Д.

При использовании EAV основная часть информации сохраняется в двух таблицах, называемых, скажем, таблицей Product и таблицей ProductAttributes:

Product table  
   "ProductID" (primary key, the "EntityId")
    "TypeId" 
    optionally, some common attributes found in all/most other Products, say...
      price
      ManufacturerId
      Photo

ProductAttributes table
    "ProductID" (Foreign Key to Product table)
    "AttributeID"  (FK to Attribute table)
    "Value"   (actual value; note: sometimes we can have several SQL fields for
               this say IntValue, StringValue, DateValue, allowing to store 
               values in their natural format)

Приведенные выше таблицы составляют большую часть данных и дополняются таблицами, в которых хранится [логическая] схема каталога, также известная как "метаданные". Эти таблицы включают в себя:

  • Таблица атрибутов, в которой определены атрибуты: имя, тип данных, isRequired и т. Д.
  • Таблица типов, в которой определены типы (категории): Имя, возможно, родительский тип в случае иерархических онтологий.
  • Type_Attributes, где перечислены возможные атрибуты для данного типа (например: "Телевизор" имеет атрибут "Количество каналов", "Размер экрана" и т. Д., А "Видеомагнитофон" имеет атрибут "Количество головок", "Поддерживаемый формат")., "Цвет кузова" и т. Д.

Все это может показаться несколько сложным по сравнению с традиционным подходом, согласно которому логическая схема "жестко закодирована" в схеме SQL, т.е. у нас есть одна таблица "TVSets" с набором столбцов, по одному на атрибут, а затем таблица "VCR" с свой собственный, другой набор столбцов / атрибутов. Однако при таком подходе логика приложения каким-то образом приводит к жесткому кодированию (если только через косвенное отображение на карте сортов) имен таблиц и столбцов.
Напротив, модель EAV позволяет программе обнаруживать список возможных типов и, для каждого типа, список возможных атрибутов (либо обязательных, либо необязательных). Кроме того, поскольку все значения атрибутов хранятся в одной и той же таблице, можно фильтровать атрибуты независимо от типа (или подтипа) продукта. Например, чтобы получить все предметы дешевле, чем 50 долларов (в другом подходе нам, возможно, пришлось искать в десятках таблиц).

Вернуться к функции "детализации"...
Как только начальный поиск выполнен (скажем, поиск во всех продуктах, где имя [полнотекстовое индексирование] содержит слово "экран"), таблица ProductAttributes может создать отдельный список всех различных атрибутов AttributeID (следовательно, имя атрибута при поиске в таблице атрибутов) для продукт, удовлетворяющий этому первому критерию поиска.
После того, как пользователь выберет данный атрибут (скажем, "Производитель"), таблица ProductAttributes может создать отдельный список производителей (вместе с количеством продуктов для каждого производителя) (альтернативно, такую ​​информацию можно искать сначала, а не лениво, когда пользователь запрашивает это).
Затем пользователь выбирает данного производителя (или нескольких), и запускается новый запрос, чтобы уменьшить начальный список результатов. Список возможных атрибутов (а внутри каждого атрибута список возможных значений) уменьшается, поскольку некоторые продукты (сущности), изначально выбранные, теперь исключаются.
Процесс продолжается, предоставляя конечному пользователю управляемый поиск в каталоге. Конечно, пользователь может отказаться и т.д.

Чтобы помочь с этим многословным объяснением (или, возможно, еще больше запутать читателя...), следующий фрагмент обеспечивает более точное указание того, как эта структура может использоваться для реализации поиска. Этот код адаптирован для имен таблиц, используемых в приведенном выше объяснении, и может содержать несколько опечаток, но, как правило, дает представление об особенностях. Кроме того, это написано с помощью общего табличного выражения (CTE), но вполне может быть записано как подзапрос. Также не то, что мы не объединяемся с таблицами логической схемы (метаданных), но это также можно сделать, чтобы получить имена атрибутов, имя типа и тому подобное непосредственно в наборе результатов.
Как указывалось ранее, запросы и логика, поддерживающие эту архитектуру, более сложны, но также более универсальны и терпимы к изменениям типа хранимых элементов и их атрибутов. Конечно, этот тип запроса генерируется динамически на основе текущего списка критериев поиска, предоставленного конечным пользователем.

WITH SearchQry AS (
  SELECT ROW_NUMBER() OVER (ORDER BY P.EntityId ASC) AS RowNum,  
         P.EntityId AS EId
         FROM  Products P
         INNER JOIN ProductAttributes PA1 ON P.EntitityId = PA1.EntityId and PA1.AttributeID = <some attribute id, say for Manufacturer> 
         INNER JOIN ProductAttributes PA2 ON P.EntitityId = PA2.EntityId and PA2.AttributeID = <some other attribute id, say for Color>
         -- here for additional PAn JOINs as more criteria is added
         WHERE  P.ProductType IN (ProdId_x, ProdId_y, ProdId_z)  -- for example where these x,y,z Ids correspond to say "TV Sets", "LapTop Computers" and "PDAs" respectively
            AND PA1.Value = 'SAMSUNG' -- for example
            AND PA2.Value = 'YELLOW' -- for example
         GROUP BY P.EntityId
   )  

SELECT  P.EntityId, PA.AttributeId, PA.Value -- PA.IntValue (if so structured)
FROM (SELECT * FROM SearchQry WHERE RowNum BETWEEN  1 AND  15)  AS S
JOIN ProductAttributes PA ON PA.EntityId = S.EId
INNER JOIN Products P on P.EntityID = PA.EntityId
ORDER BY P.EntityId, P.AttributeId  -- or some other sort order

Извините за длинное объяснение, возможно, [возможно] есть лучшее описание этого онлайн, но я не нашел его...

Вместо использования реляционной базы данных, используйте отдельную систему полнотекстового поиска для детализации или многогранного поиска, например, "Solr". Рано или поздно "группировка" станет проблемой производительности при запросе базы данных.

Стоит посмотреть

Solr Search Server

Другие вопросы по тегам