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

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

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

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

Ответ 1

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

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

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

  • Сущность (иначе продукт или элемент) = "запись" в традиционном реляционном слове
  • Атрибут = a "column" (aka "field" ) в RDBMS lingo
  • Значение = числовое (или строковое или иное) значение данного столбца для данной записи.
  • Тип (aka category) = [свободно] "таблица" в СУБД, т.е. набор записей, которые совместно используют один и тот же набор атрибутов.

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

С 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" с ее набором столбцов по одному на атрибут, а затем "видеомагнитофон" "таблица со своим, различным набором столбцов/атрибутов. Однако при таком подходе логика приложения в некотором смысле заканчивает жесткое кодирование (если только через косвенное отображение на карте) имена таблиц и столбцов.
Напротив, модель EAV позволяет программе обнаруживать список возможных типов, а для каждого типа - список возможных атрибутов (обязательный или необязательный). Кроме того, поскольку значения атрибутов хранятся в одной и той же таблице, можно фильтровать атрибуты независимо от типа (или подтипа) продукта. Например, чтобы получить все предметы дешевле, чем 50 долларов (в другом подходе нам, возможно, пришлось посмотреть десятки таблиц для этого).

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

Чтобы помочь в этом многословном объяснении (или, возможно, еще больше запутать читателя...), следующий фрагмент дает более точное указание на то, как эта структура может использоваться для реализации поиска. Этот код адаптирован для имен таблиц, используемых в объяснении выше, и может включать несколько опечаток, но в целом обеспечивает вкус вещей. Кроме того, это написано с помощью Common Table Expression (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

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

Ответ 2

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

Стоит взглянуть на

Сервер поиска Solr