2015-04-06 44 views
0

我试图通过避免包含相同单词的多个记录来限制我的数据库的大小,因此我已经构建了两个表,用于将关键字与其他行表。mySQL加入三个表并搜索一个表中找到的几个关键字

作为一个例子,我们使用follwing搜索输入:“找到我”

什么愿望去得到一个打击,是的product_id = 106 难道我只是在产品名称搜索PRODUCT_NAME?不可以,因为产品可以与其他关键字关联,而这些关键字不属于product_name的一部分。

表:ec_products

product_id | product_name | is_deleted 
--------------------------------------------- 
106   | some product | 0 

表:ec_keywords_index

word_id  | keyword 
--------------------------------------------- 
55   | find 
61   | my 
77   | product 

表:ec_keyword_relations

word_id  | application_id | related_id 
------------------------------------------------ 
55   | 1     | 106 
61   | 1     | 106 
77   | 1     | 106 

所以,我现在想,当我输入 “找我” 到我的搜索输入是:

  • 我只想要命中其中ec_keyword_relations.application_id = 1
  • 我的搜索字符串中的所有单词都应该与产品相关。例如。如果我将搜索输入更改为“找到我的裤子”,我们不应该找到product_id = 106.

这是我到目前为止尝试过的(并且我知道我离工作解决方案很远暂且):

$searchInput = 'find my'; 
    $keywords = explode(' ', $searchInput); 

    $keyword_count = count($keywords); 

    $n = 1; 
    $query = ''; 

    foreach($keywords as $keyword) { 
     if ($n !== $keyword_count) { 
      $query_ext = ' AND '; 
     } else { 
      $query_ext = ''; 
     } 

     $query .= "(ec_keywords_index.keyword LIKE '%$keyword%')" . $query_ext; 

     ++$n; 
    } 

    $query = " 
     SELECT 
      ec_products.product_name 

     FROM 
      ec_products 

     LEFT JOIN ec_search_word_relations 
      ON ec_keyword_relations.related_id = ec_products.product_id 

     LEFT JOIN ec_keywords_index 
      ON ec_keywords_index.word_id = ec_keyword_relations.word_id 

     WHERE 
      ($query) 
     AND 
      ec_products.is_deleted = '0' 
     AND 
      ec_keyword_relations.application_id = '1' 

     GROUP BY 
      ec_products.product_id 

     ORDER BY 
      ec_products.product_name ASC 

     LIMIT 
      100"; 

    $stmt = $mysqli->prepare($query); 
    $stmt->execute(); 
    $stmt->store_result(); 
    $stmt->bind_result($name); 
    while ($stmt->fetch()) { 
     echo $name; 
    } 

UPDATE:

经过一番摆弄周围,我想出了这个解决方案预期这只是工作。 (就性能而言)它是一个好的还是坏的解决方案?

$searchInput = 'find my'; 
    $keywords = explode(' ', $searchInput); 

    $keyword_count = count($keywords); 

    $n = 1; 
    $where_query = ''; 
    $having_query = ''; 

    foreach($keywords as $keyword) { 
     if ($n != $keyword_count) { 
      $w_query_ext = ' OR '; 
      $h_query_ext = ' AND '; 
     } else { 
      $w_query_ext = ''; 
      $h_query_ext = ''; 
     } 

     $where_query .= "ec_keywords_index.keyword LIKE '%" . $keyword . "%'" . $w_query_ext; 

     $having_query .= "related_keywords LIKE '%" . $keyword . "%'" . $h_query_ext; 

     ++$n; 
    } 

    $query = " 
     SELECT 
      ec_products.product_name, 
      GROUP_CONCAT(' ', ec_keywords_index.keyword) AS 'related_keywords' 

     FROM 
      ec_products, 
      ec_keywords_index 

     LEFT JOIN 
      ec_keyword_relations 
      ON ec_keyword_relations.word_id = ec_keywords_index.word_id 

     WHERE ($where_query) 
      AND ec_products.product_id = ec_keyword_relations.related_id 
      AND ec_keyword_relations.application_id = '1' 
      AND ec_products.is_deleted = '0' 

     GROUP BY 
      ec_products.product_name 

     HAVING 
      ($having_query) 

     LIMIT 
      100"; 

    $stmt = $mysqli->prepare($query); 
    $stmt->execute(); 
    $stmt->store_result(); 
    $stmt->bind_result($name); 
    while ($stmt->fetch()) { 
     echo $name; 
    } 

上面的例子输出这样的查询:

SELECT 
     ec_products.product_name, 
     GROUP_CONCAT(' ', ec_keywords_index.keyword) AS 'related_keywords' 

    FROM 
     ec_products, 
     ec_keywords_index 

    LEFT JOIN 
     ec_keyword_relations 
     ON ec_keyword_relations.word_id = ec_keywords_index.word_id 

    WHERE (ec_keywords_index.keyword LIKE '%find%' OR ec_keywords_index.keyword LIKE '%my%') 
     AND ec_products.product_id = ec_keyword_relations.related_id 
     AND ec_keyword_relations.application_id = '1' 
     AND ec_products.is_deleted = '0' 

    GROUP BY 
     ec_products.product_name 

    HAVING 
     (related_keywords LIKE '%find%' AND related_keywords LIKE '%my%') 

    LIMIT 
     100 

我使用GROUP_CONCAT创建一个包含所有与产品相关的关键字一栏,然后我的WHERE子句仅用来选择在我的搜索字符串中实际找到的关键字...然后使用HAVING子句在使用GROUP_CONCAT的列构建中进行搜索。以实例

回答

0

自己的答案:

经过一番摆弄周围,我想出了这个解决方案预期这只是工作。我不知道这是不是最佳实践,但它的作用就像一个魅力。

$searchInput = 'find my'; 
    $keywords = explode(' ', $searchInput); 

    $keyword_count = count($keywords); 

    $n = 1; 
    $where_query = ''; 
    $having_query = ''; 

    foreach($keywords as $keyword) { 
     if ($n != $keyword_count) { 
      $w_query_ext = ' OR '; 
      $h_query_ext = ' AND '; 
     } else { 
      $w_query_ext = ''; 
      $h_query_ext = ''; 
     } 

     $where_query .= "ec_keywords_index.keyword LIKE '%" . $keyword . "%'" . $w_query_ext; 

     $having_query .= "related_keywords LIKE '%" . $keyword . "%'" . $h_query_ext; 

     ++$n; 
    } 

    $query = " 
     SELECT 
      ec_products.product_name, 
      GROUP_CONCAT(' ', ec_keywords_index.keyword) AS 'related_keywords' 

     FROM 
      ec_products, 
      ec_keywords_index 

     LEFT JOIN 
      ec_keyword_relations 
      ON ec_keyword_relations.word_id = ec_keywords_index.word_id 

     WHERE ($where_query) 
      AND ec_products.product_id = ec_keyword_relations.related_id 
      AND ec_keyword_relations.application_id = '1' 
      AND ec_products.is_deleted = '0' 

     GROUP BY 
      ec_products.product_name 

     HAVING 
      ($having_query) 

     LIMIT 
      100"; 

    $stmt = $mysqli->prepare($query); 
    $stmt->execute(); 
    $stmt->store_result(); 
    $stmt->bind_result($name); 
    while ($stmt->fetch()) { 
     echo $name; 
    } 

上面的例子输出这样的查询:

SELECT 
     ec_products.product_name, 
     GROUP_CONCAT(' ', ec_keywords_index.keyword) AS 'related_keywords' 

    FROM 
     ec_products, 
     ec_keywords_index 

    LEFT JOIN 
     ec_keyword_relations 
     ON ec_keyword_relations.word_id = ec_keywords_index.word_id 

    WHERE (ec_keywords_index.keyword LIKE '%find%' OR ec_keywords_index.keyword LIKE '%my%') 
     AND ec_products.product_id = ec_keyword_relations.related_id 
     AND ec_keyword_relations.application_id = '1' 
     AND ec_products.is_deleted = '0' 

    GROUP BY 
     ec_products.product_name 

    HAVING 
     (related_keywords LIKE '%find%' AND related_keywords LIKE '%my%') 

    LIMIT 
     100 

我使用GROUP_CONCAT创建一个包含所有与产品相关的关键字一栏,然后我的WHERE子句仅用来选择在我的搜索字符串中实际找到的关键字...然后使用HAVING子句在使用GROUP_CONCAT的列构建中进行搜索。