分面搜索计数

时间:2013-12-27 07:31:24

标签: php mysql faceted-search

我想创建分面搜索。 我有一些MySQL表:

**products_table**
id   name          category_set
9    Female.Jeans  157
10   Male.Jeans    157

**fields_table**
id   name
1    Color
2    Gender

**fields_values_table**
id   fieldsid   value
1    1          White
2    1          Black
3    1          Orange
4    1          Green
5    1          Blue
6    2          Male
7    2          Female

**products_to_fields_values**
productid   fields_values_id
9           5
9           7
10          5
10          6

我有php功能来搜索我的产品:

private function get_products ($filter) {

        $per_page   = (isset($filter["show_by"]) && $filter["show_by"] >= 25 && $filter["show_by"] <= 100) ? intval($filter["show_by"]) : 25; 
        $start  = (isset($filter["page_id"]) && intval($filter["page_id"])) ?  ($filter["page_id"] -1)*$per_page : 0;

        $data           = [];

        $search_vids    = false;
        if (isset($filter['vid']) && is_array($filter['vid'])) {

            $in_set = implode(',', array_filter($filter['vid']));

            if (strlen($in_set)) {
                $search_vids = true;
            }
        }

        if ($search_vids) {

            $sql_counter    = 'SELECT COUNT(*) count FROM `products` WHERE 1=1';
            $sql_result = 'SELECT 
                                        P.id,
                                        P.name, 
                                        P.status                                        
                                    FROM `products` P, `products_to_fields_values` V WHERE 1=1';
        } else {

            $sql_counter    = 'SELECT COUNT(*) count FROM `products` WHERE 1=1';
            $sql_result = 'SELECT 
                                        `id`, 
                                        `name`, 
                                        `status`
                                    FROM `products` WHERE 1=1';
        }

        if ($search_vids) {

            $sql_counter    .= ' AND P.id = V.productid AND V.fields_values_id IN ('.$in_set.')';
            $sql_result     .= ' AND P.id = V.productid AND V.fields_values_id IN ('.$in_set.')';
        }

        if (isset($filter['cid']) && intval($filter['cid'])) {

            $sql_counter    .= ' AND FIND_IN_SET(:cid, `category_set`)';
            $sql_result     .= ' AND FIND_IN_SET(:cid, `category_set`)';
            $data[':cid'] = $filter['cid'];
        }

        if (isset($filter['price']['from']) && floatval($filter['price']['from'])) {

            $sql_counter    .= ' AND `price` >= :price_from END ';
            $sql_result     .= ' AND `price` >= :price_from END ';

            $data[':price_from'] = $filter['price']['from'];
        }

        if (isset($filter['price']['to']) && floatval($filter['price']['to'])) {

            $sql_counter    .= ' AND `price` <= :price_to ';
            $sql_result     .= ' AND `price` <= :price_to ';

            $data[':price_to'] = $filter['price']['to'];
        }

        if (isset($filter['q']) && strlen($filter['q']) > 0) {

            $search          = filter_var($filter['q'], FILTER_SANITIZE_STRING);

            $sql_counter    .= ' AND (`name` LIKE concat("%", :search_name, "%")';
            $sql_result     .= ' AND (`name` LIKE concat("%", :search_name, "%")';

            $sql_counter    .= ' OR `product_tag` LIKE concat("%", :search_tag, "%"))';
            $sql_result     .= ' OR `product_tag` LIKE concat("%", :search_tag, "%"))';

            $data[':search_name']  = $search;
            $data[':search_tag']      = $search;
        }   

        $count  = $this->db1->query($sql_counter)->single($data)['count'];

        if ($search_vids) {
            $sql_result             .= ' GROUP BY P.id LIMIT :start, :perpage';
        } else {
            $sql_result             .= ' LIMIT :start, :perpage';
        }

        $data[':start']     = $start;
        $data[':perpage']   = $per_page;

        $rows   = $this->db1->query($sql_result)->resultset($data);
        $pages = ($count >0) ? ceil($count/$per_page) : 0;

        $product_list       = array();
        $fields                 = array();
        $breadcrumbs    = array();

        $cid                    = 0;

        if(count($rows)>0) {
            foreach ($rows as $row) {
                $product_list[]             = $row;
            } 
        }

        $categories                 =   new categories($this->app, $this->user);
        $categories_arr             =   $categories->load();


        if (isset($filter['cid']) && intval($filter['cid'])) { // Categories page

            $sql                = 'SELECT GROUP_CONCAT(fieldid) AS fields_set FROM `fields_to_categories` WHERE `category_set`= :cid';
            $fields_ids     = $this->db1->query($sql)->bind(':cid', $filter['cid'])->single();

            if (isset($fields_ids['fields_set']) && !empty($fields_ids['fields_set'])) {

                $fields         =   new fields($this->app, $this->user);
                $fields         =   $fields->load_controller($fields_ids['fields_set'], false); // False = fields with status = 1
            }

            $breadcrumbs= $categories->getBreadcrumbs($filter['cid']); 

        } else {    

            $breadcrumbs= $categories->getBreadcrumbs($cid); 
        }


        return array(
            'products'          => $product_list,
            'categories'        => $categories_arr["categories"],           
            'filter'                => isset($filter['cid']) && intval($filter['cid']) && isset($fields['fields']) ? $fields['fields'] : '',
            'breadcrumbs'   => isset($breadcrumbs['path']) ? $breadcrumbs['path'] :'',
            'total'             => $count,
            'pages'             => intval($pages),
            'status'                => 1
        );
    }

这会给我一张照片: enter image description here 但问题出在这里:

当我检查男性(1个产品)时,蓝色应为1.请检查下图。 如何修复我的搜索功能? enter image description here

1 个答案:

答案 0 :(得分:1)

您的查询问题是,如果产品与单个过滤器匹配,它将返回产品。

由于您需要匹配所有过滤器,因此您需要对查询进行一些更改

这可以通过2种方式实现

  1. 为每个过滤器创建派生表,然后匹配那些派生表
  2. 计算每个产品匹配的过滤器数量,只有在匹配特定数量的过滤器时才会返回。使用小提琴的示例查询

    select 
        pfv.productid, pt.name
    from 
        fields_table ft 
    inner join 
        fields_values_table fvt 
    on 
        (ft.id=fvt.fieldsid) 
    inner join 
        products_to_fields_values pfv 
    on  
        (pfv.fields_values_id=fvt.id) 
    inner join 
        products_table pt 
    on 
        (pt.id=pfv.productid) 
    inner join
        product p
    on
        (p.productid=pt.id) <-- Assuming product table having price and 1-1 mapping
    where 
        p.price > 500 and p.categoryid=102 and
        (ft.name='color' and fvt.value='Blue')or 
        (ft.name='gender' and fvt.value='female')
    group by 
        pfv.productid, pt.name
    having count(*)>=2  <--Maintain the count of how many field value filters it should match. In this example we have only 2 filters
    
  3. Fiddle (更新小提琴)

    | PRODUCTID |         NAME |
    |-----------|--------------|
    |         9 | Female.Jeans |