【问题标题】:mysql search title, description and multi rows tag (regarding conditions)mysql搜索标题,描述和多行标签(关于条件)
【发布时间】:2016-11-05 21:56:39
【问题描述】:

我想实现类似mysql search title, description and multi rows tag的搜索。

这是我的桌子:

书籍

+----+-----------------------+-------------+
| id | name                  | description | 
+----+-----------------------+-------------+
|  1 | Me Before You         | [TEXT]      |
|  2 | How To Win Friends... | [TEXT]      |
|  3 | The Girl on the Train | [TEXT]      |
|  4 | After You             | [TEXT]      |
|  5 | We Were Liars         | [TEXT]      |
+----+-----------------------+-------------+

标签

+----+-----------------------+
| id | tag                   |
+----+-----------------------+
|  1 | romance               |
|  2 | thriller              |
|  3 | fantasy               |
|  4 | science fiction       |
|  5 | drama                 |
|  6 | friends               |
+----+-----------------------+

书籍标签

+---------+--------+
| book_id | tag_id |
+---------+--------+
|       1 |      1 |
|       1 |      3 |
|       2 |      3 |
|       3 |      3 |
|       3 |      5 |
|       4 |      1 |
|       4 |      5 |
|       4 |      6 |
|       5 |      2 |
|       5 |      6 |
+---------+--------+

以下是一些示例搜索和所需结果:

'romance'       -> books 1, 4
'friends'       -> books 2, 4, 5
'friends win'   -> books 2
'fantasy'       -> books 2, 3
'fantasy train' -> books 3

在构建 SQL 查询之前,函数会同时检查每个给定的关键字,如果它甚至是一个标签。例如,在这种情况下,我的问题是:

  • 案例:3 /
  • 关键词:朋友赢 /
  • 标签:朋友

查询:

SELECT SQL_CALC_FOUND_ROWS 
    b.id, b.name, 
    MATCH(b.name) AGAINST('*friends* *win*' IN BOOLEAN MODE) as name_score,
    MATCH(t.tag) AGAINST('friends' IN BOOLEAN MODE)as tag_score
FROM 
    books b
LEFT JOIN 
    books_tags bt ON bt.book_id = b.id
LEFT JOIN 
    tags t ON t.id = bt.tag_id 
WHERE  
    MATCH(b.name) AGAINST('*friends win*' IN BOOLEAN MODE)
    OR MATCH(t.tag) AGAINST('friends' IN BOOLEAN MODE)
GROUP BY 
    b.id
ORDER BY 
    name_score DESC, (tag_score + name_score) DESC

结果:

array (size=3)
  0 => string '2' (length=1)
  1 => string '4' (length=1)
  2 => string '5' (length=1)

在这种情况下,关键字“朋友”已经与标题匹配,因此必须减少条件,不应再搜索标签。我该如何解决?

【问题讨论】:

  • 你想解决/避免什么问题?
  • 如果关键字已经匹配标题,标签条件OR MATCH(t.tag) AGAINST('friends' IN BOOLEAN MODE)必须被忽略,因为重点是心情。
  • 但那又怎样?为什么这有关系?性能?
  • 没有。这都是关于结果的。如果关键字与标题匹配,则该关键字已过时,不得包含在搜索条件中。在我的示例中,结果是书 2、4 和 5,但必须只有书 2。

标签: php mysql search tags conditional-statements


【解决方案1】:

好的,最后我写了一个函数,它为我生成了一个有效的查询。该功能非常复杂,取决于多个用户输入。 解决方案是连接 t.tag 和 b.name。这就是我的 WHERE 条件的样子,它对我来说很好:

... WHERE ap.active='yes'
AND (LOWER(CONCAT_WS(' ', IF(LENGTH(t.tag), t.tag, NULL), IF(LENGTH(b.name), b.name, NULL) )) REGEXP 'friends'
AND LOWER(CONCAT_WS(' ', IF(LENGTH(t.tag), t.tag, NULL), IF(LENGTH(b.name), b.name, NULL) )) REGEXP 'win')
GROUP BY b.id

【讨论】:

    【解决方案2】:

    这就是你所追求的吗?...

    数据集

    DROP TABLE IF EXISTS books;
    
    CREATE TABLE books
    (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
    ,name VARCHAR(50) NOT NULL
    ,FULLTEXT(name)
    ) ENGINE = MyISAM;
    
    INSERT INTO books VALUES
    (1,'Me Before You'),
    (2,'How To Win Friends...'),
    (3,'The Girl on the Train'),
    (4,'After You'),
    (5,'We Were Liars');
    
    DROP TABLE IF EXISTS tags;
    
    CREATE TABLE tags
    (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
    ,tag VARCHAR(20) NOT NULL
    );
    
    INSERT INTO tags VALUES
    (1,'romance'),
    (2,'thriller'),
    (3,'fantasy'),
    (4,'science fiction'),
    (5,'drama'),
    (6,'friends');
    
    DROP TABLE IF EXISTS books_tags;
    
    CREATE TABLE books_tags
    (book_id INT NOT NULL
    ,tag_id INT NOT NULL
    ,PRIMARY KEY(book_id,tag_id)
    );
    
    INSERT INTO books_tags VALUES
    (1,1),
    (1,3),
    (2,3),
    (3,3),
    (3,5),
    (4,1),
    (4,5),
    (4,6),
    (5,2),
    (5,6);
    

    查询和结果

    SELECT DISTINCT b.*
                  , MATCH(b.name) AGAINST('*friends* *win*' IN BOOLEAN MODE) name_score
               FROM books b 
               LEFT 
               JOIN books_tags bt 
                 ON bt.book_id = b.id 
               LEFT 
               JOIN tags t 
                 ON t.id = bt.tag_id 
                AND t.tag IN ('friends','win') 
              WHERE t.id IS NULL;
    
    +----+-----------------------+------------+
    | id | name                  | name_score |
    +----+-----------------------+------------+
    |  1 | Me Before You         |          0 |
    |  2 | How To Win Friends... |          1 |
    |  3 | The Girl on the Train |          0 |
    |  4 | After You             |          0 |
    |  5 | We Were Liars         |          0 |
    +----+-----------------------+------------+
    

    【讨论】:

      猜你喜欢
      • 2012-07-25
      • 2022-06-14
      • 1970-01-01
      • 1970-01-01
      • 2012-08-24
      • 2014-12-17
      • 2013-05-28
      • 2015-07-14
      • 1970-01-01
      相关资源
      最近更新 更多