【问题标题】:Design Pattern for Drilldown / Filtered Search向下钻取/过滤搜索的设计模式
【发布时间】:2011-01-21 23:19:48
【问题描述】:

我希望为网站构建一个强大的搜索功能,类似于 NewEgg 的钻取搜索,例如,

http://www.newegg.com/Product/ProductList.aspx?Submit=ENE&N=2010150014%201035507776&name=7200%20RPM

我正在处理与具有不同标准的产品类似的各种对象。谁能推荐一个好的设计来构建像 NewEgg 这样的搜索引擎?

【问题讨论】:

  • 什么是下钻搜索?一个您可以在结果中搜索的地方?请指定(您认为)进行良好搜索所必需的条件。
  • 一组项目具有可以搜索的独特属性。例如,对于硬盘驱动器,您可以按 RPM(5400、7200、10,000 等)进行过滤,但对于显示器,您可以按屏幕尺寸(17"、19"、22" 等)进行过滤。每个项目都有不同的设置可以过滤的属性可能是项目类型独有的。

标签: php search


【解决方案1】:

“垂直”存储数据,即以Entity-Attribute-Value (EAV) 格式存储数据,以及隐含在 EAV 中的 [元] 数据驱动模式管理,提供了一个框架,其中每个产品的属性彼此“独立” .这反过来又促进了下钻的实施(即查询的引导细化,其中在每一步向最终用户提供仍然适用的可能属性列表,对于每个这样的属性,可能值的列表)。

需要注意的是,这更适用于较小的目录(例如少于 100 万个产品),因为 EAV 模型可能会在较大的数据库中引入一些性能和/或扩展问题。关注性能的实际大小因目录的具体情况而异(每个产品的平均属性数量、不同类型产品之间的属性共性、“本体”的一般复杂性等),但 EAV 是较小的目录的方法。除了对“向下钻取”过滤的支持外,它还引入了灵活的数据模式(添加/删除属性和/或产品类型等的能力,无需更改物理(数据库)模式;只有逻辑模式是改变)。

编辑:有关 EAV 的更多详细信息/资源
诚然,关于它的维基百科文章有些抽象......
简而言之,该模型确定了以下概念:

  • 实体(也称为产品或项目)= 传统关系术语中的“记录”
  • 属性 = RDBMS 术语中的“列”(又名“字段”)
  • Value = 给定记录的给定列的数字(或字符串或其他)值。
  • 类型(又名类别)= [松散地] RDBMS 中的“表”,即通常共享同一组属性的一组记录。

例如,用电子产品目录来说明这一点,实体可以是特定的“平板显示器”,其类型可以是“显示设备”,其属性可以是“尺寸”、“分辨率”、“价格”等.

使用 EAV,大部分信息存储在两个表中,分别称为 Product 表和 ProductAttributes 表:

Product table  
   "ProductID" (primary key, the "EntityId")
    "TypeId" 
    optionally, some common attributes found in all/most other Products, say...
      price
      ManufacturerId
      Photo

ProductAttributes table
    "ProductID" (Foreign Key to Product table)
    "AttributeID"  (FK to Attribute table)
    "Value"   (actual value; note: sometimes we can have several SQL fields for
               this say IntValue, StringValue, DateValue, allowing to store 
               values in their natural format)

上述表格构成了大部分数据,并辅以存储目录[逻辑]模式的表格,也称为“元数据”。这些表格包括:

  • 定义属性的属性表:名称、数据类型、isRequired 等。
  • 定义类型(类别)的类型表:名称,在分层本体的情况下可能是父类型。
  • Type_Attributes 列出了给定类型的可能属性(例如:“电视机”具有属性“频道数”、“屏幕尺寸”等,“VCR”具有属性“头数”、“支持的格式”、“主体颜色”等。

与逻辑模式在 SQL 模式中“硬编码”的传统方法相比,所有这些看起来有些复杂,即我们有一个“TVSets”表,每个属性都有一个列集,然后是一个“VCR” " 具有自己的不同列/属性集的表。然而,通过这种方法,应用程序逻辑最终会以某种方式(如果只是通过排序映射中的间接)对表名和列名进行硬编码。
相反,EAV 模型允许程序发现可能类型的列表,并且对于每种类型,可能的属性列表(必需的或可选的)。此外,由于属性值都存储在同一个表中,因此可以过滤属性而不考虑产品的类型(或子类型)。例如,要使所有商品的价格低于 50 美元(在另一种方法中,我们可能不得不查看十几张桌子)。

回到“向下钻取”功能...
一旦执行了初始搜索(比如搜索名称 [全文索引] 包含单词“screen”的所有产品),ProductAttributes 表可以生成所有不同 AttributeID 的不同列表(因此通过在 Attributes 表中查找的属性名称)满足第一个搜索条件的产品。
在用户选择给定属性(比如“制造商”时,ProductAttributes 表可以生成不同的制造商列表(以及每个制造商的产品数量)。(或者,当用户请求)。
然后用户选择一个给定的制造商(或几个),并运行一个新的查询来减少初始结果列表。可能的属性列表(以及每个属性中可能值的列表)减少了,因为最初选择的一些产品(实体)现在被排除在外。
该过程继续进行,为最终用户提供对目录的引导式搜索。当然用户可以回溯等。

可能有助于解释这个冗长的解释(或者可能会进一步混淆读者......)下面的 sn-p 提供了一个更精确的指示这个结构可以用于实现搜索的方式。此代码适用于上述说明中使用的表名,可能包含一些拼写错误,但通常提供事物的味道。此外,这是使用公用表表达式 (CTE) 编写的,但也可以编写为子查询。也不是我们不加入逻辑模式(元数据)表,但也可以这样做,直接在结果集中获取属性名称、类型名称等。
如前所述,支持此架构的查询和逻辑更加复杂,但也更加通用,并且能够容忍存储的项目类型及其属性的变化。当然,这种类型的查询是根据最终用户提供的当前搜索条件列表动态生成的。

WITH SearchQry AS (
  SELECT ROW_NUMBER() OVER (ORDER BY P.EntityId ASC) AS RowNum,  
         P.EntityId AS EId
         FROM  Products P
         INNER JOIN ProductAttributes PA1 ON P.EntitityId = PA1.EntityId and PA1.AttributeID = <some attribute id, say for Manufacturer> 
         INNER JOIN ProductAttributes PA2 ON P.EntitityId = PA2.EntityId and PA2.AttributeID = <some other attribute id, say for Color>
         -- here for additional PAn JOINs as more criteria is added
         WHERE  P.ProductType IN (ProdId_x, ProdId_y, ProdId_z)  -- for example where these x,y,z Ids correspond to say "TV Sets", "LapTop Computers" and "PDAs" respectively
            AND PA1.Value = 'SAMSUNG' -- for example
            AND PA2.Value = 'YELLOW' -- for example
         GROUP BY P.EntityId
   )  

SELECT  P.EntityId, PA.AttributeId, PA.Value -- PA.IntValue (if so structured)
FROM (SELECT * FROM SearchQry WHERE RowNum BETWEEN  1 AND  15)  AS S
JOIN ProductAttributes PA ON PA.EntityId = S.EId
INNER JOIN Products P on P.EntityID = PA.EntityId
ORDER BY P.EntityId, P.AttributeId  -- or some other sort order

对不起,解释太长了,网上可能[可能]有更好的描述,但我没有找到...

【讨论】:

  • 你能把我链接到 EAV 上的任何资源吗?
  • 喜欢,感谢系统的详细介绍!这对我的项目非常有帮助。
  • @Kirk:很高兴为您提供帮助。请参阅添加的 sn-p 为这种方法提供“风味”。我希望我能找到一些有关 EAV 模型的实用解释的在线参考,适用于商店目录;我可能没有找对地方;-)
  • @mjv:Magento 广泛使用 EAV,但是它们确实通过表而不是列来破坏“值”的数据类型(就 EAV 而言,我认为这更有效)。我确信他们有某种解释 EAV 的文档。
【解决方案2】:

不要使用关系数据库,而是使用独立的全文搜索引擎进行深入搜索或分面搜索,例如“Solr”。查询数据库时,“分组”迟早会成为性能问题。

值得一看

Solr Search Server

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-03-23
    • 1970-01-01
    • 2011-08-28
    • 1970-01-01
    • 2018-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多