2015-04-06 43 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的列構建中進行搜索。