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

时间:2013-08-21 01:00:02

标签: sql sql-server-2008 faceted-search

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

数据库结构如下: enter image description here

来自PRODUCT表的数据将通过TAG表中的标签进行搜索。可在TAG表中找到的值如下:

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

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

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

  1. 仅与所选标签相关的产品,无论是单个还是多个
  2. 剩余标记,也可用于选择已由单个或多个选定标记细化的产品。
  3. 如果可能的话,我希望这是所有的in-in SQL服务器,2作为存储过程分开。

    现在大多数网站都内置了这个功能,即:http://www.gnc.com/family/index.jsp?categoryId=2108294&cp=3593186.3593187(他们称之为'Narrow By')

    我一直在寻找一段时间如何做到这一点,而且我猜测如果必须以这种性质创建存储过程,那么需要有一个接受CSV值的参数,比如这样:

     [dbo].[GetFacetedProducts] @Tags_Selected = '1,3,5'
     [dbo].[GetFacetedTags] @Tags_Selected = '1,3,5'
    

    因此,使用这种架构,是否有人知道需要为这些存储过程编写哪些类型的查询,或者架构是否存在任何缺陷?有没有人在此之前创建了分面搜索?如果是这样,需要什么类型的查询来制作这样的东西?我想我只是无法绕过它,并且没有太多的东西可以向某人展示如何制作这样的东西。

3 个答案:

答案 0 :(得分:3)

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

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

答案 1 :(得分: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并动态执行它,不要这样做。

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

的产品
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,则可以将其加回到products表中,否则您就完成了。

对于您的第二个查询,一旦您拥有匹配的产品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)

答案 2 :(得分:0)

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

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

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

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

然而,使用Solr存在一些主要缺点。主要问题是你不仅需要设置另一个平台(Solr),还要设置随之而来的所有随身物品 - Java和某种Java servlet(其中有几种)。虽然Solr在Windows上运行得相当不错,但您仍然很快就会发现自己沉浸在命令行的世界中,并编辑配置文件和环境变量,这将提醒您所有关于20世纪80年代的优点......或者可能不是。当这一切都工作时,你需要使用各种方法将产品数据导出到它 - 有一个SQL Server连接器工作得相当好,但许多人更喜欢以XML格式发布数据。然后你必须在你的应用程序上创建一个webservice类型的进程,向它发送用户的查询并解析得到的匹配列表并重新计入你的应用程序(同样,XML可能是最好的方法)。

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