ストアフロント Web アプリケーションを開発しています。潜在的な顧客が Web サイトで製品を閲覧している場合、データベースから一連の類似製品を自動的に提案したいと考えています (製品類似データ/マッピングを人間が明示的に入力する必要はありません)。
実際、考えてみると、ほとんどのストアフロント データベースには、すでに多くの類似データが用意されています。私の場合Products
は次のようになります。
Manufacturer
(別名Brand
)にマッピングされ、- 1 つ以上
Categories
の にマップされ、 - 1 つ以上
Tags
(別名Keywords
) にマップされます。
製品と他のすべての製品との間で共有される属性の数を数えることで、顧客が閲覧している製品と他の製品を比較するための「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 の達人に次の質問をします。
- このユースケースで共通テーブル式(CTE) は適切/最適ですか? (それらは確かにSQLを読みやすく/従うのを容易にするようです)。上記のモデルのどこかに結合を保存する方法はありますか?
と
- これは、インデックス付きビュー (永続化のため) の良い候補になるでしょうか?それとも、ソース データの変更に過度のコストがかかるでしょうか?
SimilarProductMappings
その場合、これを任意の製品の物理テーブルを更新するストアド プロシージャにします。