6

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

数据库结构是这样的: 在此处输入图像描述

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

 ID      NAME
 ----------------------
 1       Blue
 2       Green
 3       Small
 4       Large
 5       Red

它们将通过 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'

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

4

3 回答 3

3

可以在 SQL Server 中进行分面搜索。但是,不要尝试使用您的实时产品数据表。而是创建一个非规范化的“事实”表,其中包含每个产品(行)和每个标签(列),以便交集是您的产品标签值。您可以定期从主产品表中重新填充它。

然后,为用户检查的每个标签获取匹配记录的方面计数是直接且相对有效的。

我所描述的方法非常适合小型案例,例如 1,000 个产品行和 50-100 个标签(属性)。即将推出的 SQL Server 2014 也有一个有趣的机会,它可以将表放在内存中 - 这应该允许更大的事实表。

我也使用过 Solr,正如 STW 指出的那样,这是用于方面搜索的“正确”工具。它比 SQL Server 解决方案快几个数量级。

但是,使用 Solr 有一些主要缺点。主要问题是您不仅必须设置另一个平台(Solr),还必须设置所有与之配套的工具 - Java 和某种 Java servlet(其中有几个)。虽然 Solr 在 Windows 上运行得非常好,但您很快就会发现自己沉浸在命令行和编辑配置文件和环境变量的世界中,这会让您想起 1980 年代的所有美好……或者可能不会。当一切正常时,您需要使用各种方法将产品数据导出到它 - 有一个 SQL Server 连接器,它工作得相当好,但许多人更喜欢将数据作为 XML 发布到它。然后你必须在你的应用程序上创建一个 webservice 类型的进程来发送给用户'

因此,如果您的数据集相对较小,我会坚持使用 SQL Server。您仍然可以获得亚秒级的响应,并且 SQL 2014 有望允许更大的数据集。如果您的数据集很大,那么 Solr 将提供非常快的结果(确实非常快),但准备好在学习和支持全新平台方面进行重大投资。

于 2013-12-15T07:07:51.030 回答
3

用于分面搜索的 RDBMS 是手头工作的错误工具。分面搜索是一种多维搜索,很难用基于集合的SQL语言来表达。使用数据立方体或类似的东西可能会为您提供一些所需的功能,但构建起来需要相当多的工作。

当我们面临类似的需求时,我们最终决定使用 Apache Solr 搜索引擎,它支持分面以及许多其他面向搜索的功能和特性。

于 2013-08-21T01:14:06.413 回答
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

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

相反,让我们假设同一个标签不能两次应用于一个产品,所以我们可以将问题更改为:Find me products where the number of tags matching (dynamic list) is equal to the number in in (dynamic list) )

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

这仅返回与您的所有标签匹配的产品的 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)
于 2013-08-21T03:07:52.870 回答