【问题标题】:MySQL and faceted navigation (filter by attributes)MySQL 和分面导航(按属性过滤)
【发布时间】:2010-12-22 07:24:46
【问题描述】:

我觉得这个问题可能已经被问过一千次了,所以如果它得到了回答,我深表歉意。如果是这样,有人能指出我正确的帖子/链接吗?

我正在尝试为我的网站构建一个多面导航。它使用 MySQL,这是我正在使用的表的粗略草图:

产品:
- ID
- 标题
- 描述
属性:
- product_id
- 姓名
- 价值
类别: - ID - 姓名 products_to_categories: - product_id - 类别 ID

我要做的是在您处于某个类别时显示可用属性列表,允许您为每个属性选择一个或多个值。举个例子,看看 Office Depot 的这个页面:http://www.officedepot.com/a/browse/binders/N=5+2177/

到目前为止,我已经使用了很多连接来过滤多个属性:

选择产品。*,a_options。* FROM products_to_categories AS pc, products, attributes AS a_options, /* 我可以继续完善的属性/值对列表 */ attributes AS a_select1 /* 第一个选择的属性 */ attributes AS a_select2 /* 第二个选择的属性 */ ... 哪里 pc.category_id = 1 AND products.id = pc.product_id 和 a_options.product_id = products.id AND a_options.name != '颜色' AND a_options.name != '尺寸' 和 a_select1.product_id = products.id AND a_select1.name = '颜色' AND (a_select1.value = '蓝色' OR a_select1.value = '黑色') 和 a_select2.product_id = products.id AND a_select2.name = '大小' AND a_select2.value = '8.5 x 11'

基本上a_options 将返回那些产品的所有属性,这些属性是我使用a_select1a_select2 应用的过滤器的子集。因此,如果我使用 Office Depot 中的 Binders 示例,我想在为颜色选择蓝色或黑色并为尺寸选择“8.5 x 11”后显示所有可用属性。

然后我使用 PHP 代码删除重复项并将生成的属性排列成这样的数组:

属性[name1] = (val1, val2, val3, ...) 属性[name2] = (val1, val2, val3, ...)

有没有一种方法可以加快查询速度或更有效地编写查询?我在属性表(以及所有 ID 号)中设置了名称和值的索引。但是如果有人选择了几个属性,那么查询就会运行缓慢。

提前感谢您的帮助,
斯里达尔

【问题讨论】:

    标签: mysql multiple-tables faceted-search


    【解决方案1】:

    “然后我使用 PHP 代码删除重复项”

    然后它不会扩展。

    在我阅读http://www.amazon.com/Data-Warehouse-Toolkit-Techniques-Dimensional/dp/0471153370 之后,我不停地推出构面和过滤机制。

    基本思想是您使用星型模式..

    您创建一个存储事实的事实表

    customerid | dateregisteredid | datelastloginid
    1 | 1 | 1
    2 | 1 | 2
    

    您在存储属性的维度表中使用外键

    date_registered
    Id | weekday | weeknumber | year | month | month_year | daymonth | daymonthyear
    1 | Wed      | 2            | 2009 | 2   |2-2009      | 4        | 4-2-2009
    

    然后,无论您使用哪个日期“范式”,从该维度表中获取所有 id,然后

     select * from the fact table where the fact.dateregisteredid is IN( ... the ids from the date dimension table that represent your time period)
    

    您的数据的这些“索引视图”应驻留在单独的数据库中,并且对生产中的对象的更改应将该记录排队以在分析系统中重新索引。大型站点可能会在非高峰时间将他们的记录批量发送到统计报告应用程序,但总是滞后几个小时或几天。如果架构支持,我总是尽量保持第二。

    如果您要显示行数预览,您可能还需要实施一些优化或缓存。

    总的来说,你复制数据并进行非规范化。该技术的名称为“数据仓库”或 OLAP(在线分析处理)。

    有更好的方法,使用像 Oracle 这样的商业数据库,但星型模式让任何拥有开源关系数据库的人都可以在一段时间内使用它。

    您绝对应该阅读该工具包,但他讨论了很多可以为您节省大量时间的内容。类似于处理更新数据的策略,以及在报告应用程序中保留审计历史记录。对于每个问题,他都概述了多种解决方案,每种解决方案都适用于不同的环境。

    如果您不采取简单的方法并使用大量不必要的联接,它可以扩展到数百万行。

    【讨论】:

    • 它是 ROLAP,准确地说是(关系 OLAP),因为数据仍然存储在关系结构中,而 OLAP 意味着将其存储在多维立方体中。
    【解决方案2】:

    您可以根据规范化的数据库表生成分面表。
    例如:

    > SELECT * FROM product_facet
    product_id | facet_type | facet_value
    1          | color      | blue
    2          | color      | blue
    3          | color      | green
    4          | color      | yellow
    1          | speed      | slow
    2          | speed      | slow
    

    然后只需执行以下查询即可获得每个属性的总数:

    SELECT facet_type, facet_value, COUNT(facet_value) as total
    FROM product_facet
    GROUP BY facet_type, facet_value;
    

    结果:

    facet_type | facet_value | total
    color      | blue        | 2
    color      | green       | 1
    color      | yellow      | 1
    speed      | slow        | 2
    

    使用条件搜索时,可以通过匹配产品id选择分面表:

    SELECT facet_type, facet_value, COUNT(facet_value) as total
    FROM product_facet
    WHERE product_id in (SELECT product_id FROM products WHERE ... )
    GROUP BY facet_type, facet_value;
    

    【讨论】:

    • 你的语句应该说 COUNT(facet_value) 而不是 SUM(facet_value),其余的都很好。
    • 感谢欧文的更正。我更新了我的答案。
    • 当有多个选择时,说“颜色”和“速度”。那么你的产品选择查询,即方面计数所依赖的,仍然会变得复杂。 (SELECT product_id FROM products WHERE ...)。在这里,您想要的不仅仅是颜色“蓝色”和速度“慢”的产品。如果没有自加入 Products 表,那么您的 AND sql 条件将无法工作。
    猜你喜欢
    • 1970-01-01
    • 2013-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-14
    • 1970-01-01
    相关资源
    最近更新 更多