Я разрабатываю веб-приложение магазина. Когда потенциальный клиент просматривает продукт на веб-сайте, я хотел бы предложить набор подобных продуктов из базы данных автоматически (vs требует, чтобы человек явно вводил данные/сопоставления данных о продуктах).
Фактически, когда вы думаете об этом, большинство баз данных магазина уже имеют много доступных данных о сходстве. В моем случае Products
может быть:
- отображается на
Manufacturer
(akaBrand
), - сопоставленный с одним или несколькими
Categories
, и - сопоставленный с одним или несколькими
Tags
(akaKeywords
).
Подсчитав количество общих атрибутов между продуктом и всеми другими, вы можете рассчитать "SimilarityScore" для сравнения других продуктов с тем, который просматривается клиентом. Здесь моя первоначальная реализация прототипа:
;WITH ProductsRelatedByTags (ProductId, NumberOfRelations)
AS
(
SELECT t2.ProductId, COUNT(t2.TagId)
FROM ProductTagMappings AS t1 INNER JOIN
ProductTagMappings AS t2 ON t1.TagId = t2.TagId AND t2.ProductId != t1.ProductId
WHERE t1.ProductId = '22D6059C-D981-4A97-8F7B-A25A0138B3F4'
GROUP BY t2.ProductId
), ProductsRelatedByCategories (ProductId, NumberOfRelations)
AS
(
SELECT t2.ProductId, COUNT(t2.CategoryId)
FROM ProductCategoryMappings AS t1 INNER JOIN
ProductCategoryMappings AS t2 ON t1.CategoryId = t2.CategoryId AND t2.ProductId != t1.ProductId
WHERE t1.ProductId = '22D6059C-D981-4A97-8F7B-A25A0138B3F4'
GROUP BY t2.ProductId
)
SELECT prbt.ProductId AS ProductId
,IsNull(prbt.NumberOfRelations, 0) AS TagsInCommon
,IsNull(prbc.NumberOfRelations, 0) AS CategoriesInCommon
,CASE WHEN SimilarProduct.ManufacturerId = SourceProduct.ManufacturerId THEN 1 ELSE 0 END as SameManufacturer
,CASE WHEN SimilarProduct.ManufacturerId = SourceProduct.ManufacturerId
THEN IsNull(prbt.NumberOfRelations, 0) + IsNull(prbc.NumberOfRelations, 0) + 1
ELSE IsNull(prbt.NumberOfRelations, 0) + IsNull(prbc.NumberOfRelations, 0)
END as SimilarityScore
FROM Products AS SourceProduct,
Products AS SimilarProduct INNER JOIN
ProductsRelatedByTags prbt ON prbt.ProductId = SimilarProduct.Id FULL OUTER JOIN
ProductsRelatedByCategories prbc ON prbt.ProductId = prbc.ProductId
WHERE SourceProduct.Id = '22D6059C-D981-4A97-8F7B-A25A0138B3F4'
что приводит к следующим данным:
ProductId TagsInCommon CategoriesInCommon SameManufacturer SimilarityScore
------------------------------------ ------------ ------------------ ---------------- ---------------
6416C19D-BA4F-4AE6-AB75-A25A0138B3A5 1 0 0 1
77B2ECC0-E2EB-4C1B-A1E1-A25A0138BA19 1 0 0 1
2D83276E-40CC-44D0-9DDF-A25A0138BE14 2 1 1 4
E036BFE0-BBB5-450C-858C-A25A0138C21C 3 0 0 3
Я не являюсь гуру производительности SQL, поэтому у меня есть следующие вопросы для вас: гуру SQL:
- common-table-expression (CTEs)/оптимальный в этом случае использования? (Они, похоже, облегчают чтение/выполнение SQL). Есть ли способ сохранить соединение там где-нибудь с учетом представленной выше модели?
и
- Будет ли это хорошим кандидатом для индексированного представления (for persistance) или это добавит чрезмерную стоимость изменений исходных данных? В этом случае я сделаю это хранимой процедурой, которая обновляет физическую таблицу
SimilarProductMappings
для любого данного продукта.