如何使用 SQL Server 创建分面搜索

Con*_*eak 6 sql sql-server-2008 faceted-search

我有一个应用程序,我将访问 SQL 服务器以返回数据,该数据已通过应用程序中的选择作为任何常见的分面搜索进行过滤。我确实看到了一些开箱即用的解决方案,但这些解决方案很昂贵,我更喜欢构建一些自定义的东西,但只是不知道从哪里开始。

数据库结构是这样的: 在此处输入图片说明

PRODUCT 表中的数据将通过 TAG 表中的标签进行搜索。可以在 TAG 表中找到的值将是这样的:

 ID      NAME
 ----------------------
 1       Blue
 2       Green
 3       Small
 4       Large
 5       Red
Run Code Online (Sandbox Code Playgroud)

它们将通过 ProductTag 表与产品相关联。

我需要从这个设置中返回两组数据:

  1. 仅与所选标签相关的产品,无论是单个还是多个
  2. 对于已通过单个或多个选定标签细化的产品,还可以选择剩余标签。

如果可能的话,我希望这都是内置的 SQL 服务器,2 独立为存储过程。

如今,大多数网站都内置了此功能,即:http ://www.gnc.com/family/index.jsp?categoryId=2108294&cp =3593186.3593187(他们称之为“Narrow By”)

我一直在寻找如何做到这一点,我疯狂地猜测,如果必须以这种性质创建存储过程,则需要有 1 个接受 CSV 值的参数,如下所示:

 [dbo].[GetFacetedProducts] @Tags_Selected = '1,3,5'
 [dbo].[GetFacetedTags] @Tags_Selected = '1,3,5'
Run Code Online (Sandbox Code Playgroud)

那么对于这种架构,有谁知道需要为这些存储过程编写哪些类型的查询,或者架构是否存在任何缺陷?有没有人像这样创建过分面搜索?如果是这样,做这样的事情需要什么类型的查询?我想我只是无法理解它,并且没有太多东西可以向某人展示如何制作这样的东西。

Tim*_*ers 2

您还可以在其他地方获得将 CSV 参数转换为表变量的示例。假设您已经完成了该部分,您的查询可归结为以下内容:

GetFacetedProducts:查找产品记录,其中传入的所有标签都分配给每个产品。

如果你手写它,你最终可能会得到:

SELECT P.*
FROM Product P
INNER JOIN ProductTag PT1 ON PT1.ProductID = P.ID AND PT1.TagID = 1
INNER JOIN ProductTag PT2 ON PT1.ProductID = P.ID AND PT1.TagID = 3
INNER JOIN ProductTag PT3 ON PT1.ProductID = P.ID AND PT1.TagID = 5
Run Code Online (Sandbox Code Playgroud)

虽然这确实仅选择具有这些标签的产品,但它不适用于动态列表。过去有人建立了SQL并动态执行它,不要这样做。

相反,我们假设相同的标签不能两次应用于产品,因此我们可以将问题更改为:查找我的产品,其中匹配的标签数量(动态列表)等于(动态列表)中的标签数量)

DECLARE @selectedTags TABLE (ID int)
DECLARE @tagCount int

INSERT INTO @selectedTags VALUES (1)
INSERT INTO @selectedTags VALUES (3)
INSERT INTO @selectedTags VALUES (5)

SELECT @tagCount = COUNT(*) FROM @selectedTags

SELECT
    P.ID
FROM Product P
JOIN ProductTag PT
    ON PT.ProductID = P.ID
JOIN @selectedTags T
    ON T.ID = PT.TagID
GROUP BY
    P.ID,
    P.Name
HAVING COUNT(PT.TagID) = @tagCount
Run Code Online (Sandbox Code Playgroud)

这仅返回与所有标签匹配的产品 ID,如果您想要的不仅仅是 ID,则可以将其连接回产品表,否则就完成了。

至于第二个查询,一旦获得匹配的产品 ID,您就需要列表中未包含的产品 ID 的所有标签:

SELECT DISTINCT
    PT2.TagID
FROM aProductTag PT2
WHERE PT2.ProductID IN (
    SELECT
        P.ID
    FROM aProduct P
    JOIN aProductTag PT
        ON PT.ProductID = P.ID
    JOIN @selectedTags T
        ON T.ID = PT.TagID
    GROUP BY
        P.ID,
        P.Name
    HAVING COUNT(PT.TagID) = @tagCount
)
AND PT2.TagID NOT IN (SELECT ID FROM @selectedTags)
Run Code Online (Sandbox Code Playgroud)