使用PHP,MySQL在分面搜索中计算产品计数(有效)

时间:2014-12-18 16:06:18

标签: php mysql faceted-search

假设我有一个页面显示网店中所有可用的笔记本电脑。这些结果可以通过激活某些过滤器来改进,例如品牌,价格,重量,内存量,磁盘空间等,如下所示:

Brand
[ ] Dell (16)
[ ] HP (12)
[ ] Lenovo (9)

Memory
( ) ≥ 2 GB (37)
( ) ≥ 4 GB (24)
( ) ≥ 8 GB (8)

Price
( ) ≤ 200 $ (3)
( ) ≤ 300 $ (12)
( ) ≤ 500 $ (22)

目前,我使用单个查询计算这些产品计数,其结果我在PHP中循环以将它们划分为这些类别(即"内存,≥4GB")。这种方法的问题在于,例如,"≥4GB"如果选择并显示结果,则产品计数变得不合逻辑。

MySQL(简化):

SELECT brand, memory, price FROM Laptops WHERE memory >= 4000

PHP(简化):

while($row = msqli_fetch_assoc($results)) {
    if($row['memory'] >= 2000) {
        $product_count['memory']['2gb']++;
    }
}

结果:

Memory
( ) ≥ 2 GB (24) <-- should be 37
(o) ≥ 4 GB (24)
( ) ≥ 8 GB (8)

因为我现在使用的条件类似WHERE memory >= 4000,所以产品数量仅限于当前的24个结果(与激活的过滤器相匹配),因此&#34;≥2GB& #34;现在也有24个。在24个结果中,24个将具有2 GB或更多内存,但这与用户无关,用户需要知道如果选择2 GB将显示多少结果。< / p>

我可以单独查询数据库中的每个过滤器,省略该过滤器的WHERE条件,以便其产品数量不受其自身设置的影响,但仍受其他任何过滤器(如Brand)的影响。但是,我计划至少使用十几个过滤器,这样会导致十几个查询,给相对简单的应用程序带来相对大的额外压力。

是否有更有效的方法来计算产品数量,需要更少的查询?

3 个答案:

答案 0 :(得分:2)

您需要在用户选择的任何过滤器之外构建facet查询,因为构面计数永远不会更改。您可能不会这样做,所以当用户选择4GB时,您的查询将变为:

SELECT brand, memory, price FROM Laptops WHERE memory >= 4000

应该是:

SELECT brand, memory, price FROM Laptops WHERE memory >= 2000

我建议你重新编写你的方面逻辑,不要考虑你的过滤器并优化你的查询来计算,而不是用PHP来做:

SELECT count(*) as total from Laptops WHERE memory >= 2000;
SELECT count(*) as total from Laptops WHERE memory >= 4000;

唉,如果您选择了多个过滤器,它将变得更加复杂,因为您可能想要考虑不在同一构面部分的查询中的其他过滤器。

所以...如果由品牌分面只使用此查询的内存:

SELECT count(*) as total from Laptops WHERE memory >= 2000 and brand in ('HP', 'Dell');
SELECT count(*) as total from Laptops WHERE memory >= 4000 and brand in ('HP', 'Dell');

但是对于相同结果集的品牌方面,不考虑未选择的内存:

SELECT count(*) as total from Laptops WHERE brand = 'HP';
SELECT count(*) as total from Laptops WHERE brand = 'Dell';
SELECT count(*) as total from Laptops WHERE brand = 'Lenovo';

唉,如果按品牌和内存过滤,请考虑价格:

SELECT count(*) as total from Laptops WHERE price < 200 and memory between 2000 and 4000 and brand in ('HP', 'Dell);

是的,一切正确都是特别棘手的,特别是考虑到我没有涉及你可能只想要一个选择价格但多个选择品牌的情况。这就是大多数人转向http://lucene.apache.org/solr/进行分面搜索的原因,只需返回您要求的任何字段所设置的结果集。

答案 1 :(得分:0)

我的想法是,我需要对每个可能的过滤器进行额外查询,以准确计算产品数量。但是,计数仅对当前所选过滤器(如上面的存储器)中的(无线电)选项不准确,因此如果我只是为活动过滤器重新计算产品计数(通过检查当前的$ _GET参数),则会大大减少数量必要的查询。

所以我将包含一个包含所有过滤器的查询,例如:

$query = 'SELECT id, brand, memory, price, stock FROM Laptops 
          WHERE stock > 0 AND memory >= 4000 AND price <= 200';

我将使用PHP循环将结果划分为过滤器类别并计算其计数,然后对于每个活动过滤器,我将重置这些计数并根据查询重新计算它们那个过滤器被preg_replace('(AND memory >= \d+)','',$query);等正则表达式删除了。

$query = 'SELECT id, brand, memory, price, stock FROM Laptops 
          WHERE stock > 0 AND price <= 200';

根据该查询,内存的计数现在将准确反映每个选项的结果,同时仍考虑设置的任何其他过滤器(即在内存过滤器范围之外):

Memory
( ) ≥ 2 GB (37)
(o) ≥ 4 GB (24)
( ) ≥ 8 GB (8)

现在用户知道4 GB将列表限制为24个项目,而切换到2 GB会产生更多结果。

如果没有过滤器处于活动状态,我将不需要任何额外的查询来计算产品数量。如果用户确实应用了一个或多个过滤器,我只需要为每个过滤器添加一个额外的查询,我很满意。

答案 2 :(得分:-1)

我希望问题可能是查询让我们将查询更改为下面提到并执行它。谢谢

SELECT brand, memory, price FROM Laptops WHERE memory >= 2000