跨多个索引的mysql搜索

lndjwyie  于 2021-06-19  发布在  Mysql
关注(0)|答案(2)|浏览(389)

我继承了一个大型的、丑陋的mysql 5.7数据库,并希望优化一些查询。
具体来说,用户希望搜索7个不同的 var_char 列…在7个不同的表中。
显然,我可以加入7个表并筛选 LIKE '%search term%' ,但我想用 MATCH...AGAINSTFULLTEXT 索引。
我创建了索引:

ALTER TABLE table1 ADD FULLTEXT INDEX (origname);
ALTER TABLE table2 ADD FULLTEXT INDEX (byline);
ALTER TABLE table3 ADD FULLTEXT INDEX (copyright);
ALTER TABLE table4 ADD FULLTEXT INDEX (source);
ALTER TABLE table5 ADD FULLTEXT INDEX (image_title);
ALTER TABLE table6 ADD FULLTEXT INDEX (photo_info);
ALTER TABLE table7 ADD FULLTEXT INDEX (alt_text);

我尝试了下面的方法,但是性能很差…有没有好的方法可以跨多个表进行全文搜索?

SELECT
    MATCH(table1.name) AGAINST ('search term') as name,
    MATCH(table2.byline) AGAINST ('search term') as byline,
    MATCH(table3.copyright) AGAINST ('search term') as copyright,
    MATCH(table4.source) AGAINST ('search term') as copyright,
    MATCH(table5.image_title) AGAINST ('search term') as image_title,
    MATCH(table6.photo_info) AGAINST ('search term') as photo_info,
    MATCH(table7.alt_text) AGAINST ('search term') as alt_text
FROM table1
LEFT JOIN table2 on table2.entity_id = table1.fid
LEFT JOIN table3 on table3.entity_id = table1.fid
LEFT JOIN table4 on table4.entity_id = table1.fid
LEFT JOIN table5 on table5.entity_id = table1.fid
LEFT JOIN table6 on table6.entity_id = table1.fid
LEFT JOIN table7 ON table7.alt_text = table1.fid
WHERE
    MATCH(table1.name) AGAINST ('search term') OR
    MATCH(table2.byline) AGAINST ('search term') OR
    MATCH(table3.copyright) AGAINST ('search term') OR
    MATCH(table4.source) AGAINST ('search term') OR
    MATCH(table5.image_title) AGAINST ('search term') OR
    MATCH(table6.photo_info) AGAINST ('search term') OR
    MATCH(table7.alt_text) AGAINST ('search term');

理想情况下,我只会使用elasticsearch/lucene/solr等,但让我们假设一下,我不能使用任何这些东西,我仅限于mysql。有什么好办法吗?
这是你的名字 EXPLAIN EXTENDED 输出:

id  select_type table   partitions  type    possible_keys   key key_len ref rows    filtered    Extra   
1   SIMPLE  table1  NULL    ALL NULL    NULL    NULL    NULL    557535  100 NULL    
1   SIMPLE  table2  NULL    ref entity_id   entity_id   4   mydb.table1.fid 1   100 NULL    
1   SIMPLE  table3  NULL    ref entity_id   entity_id   4   mydb.table1.fid 1   100 NULL    
1   SIMPLE  table4  NULL    ref entity_id   entity_id   4   mydb.table1.fid 1   100 NULL    
1   SIMPLE  table5  NULL    ref entity_id   entity_id   4   mydb.table1.fid 1   100 NULL    
1   SIMPLE  table6  NULL    ref entity_id   entity_id   4   mydb.table1.fid 1   100 NULL    
1   SIMPLE  table7  NULL    ALL field_file_image_alt_text_value NULL    NULL    NULL    203374  100 Using where

===========================================
回答:bomar下面的解决方案是正确的方法,但是MySQL5.7不喜欢他的语法。我必须这样编码:
选择fid,scoredname作为分数,origname作为“文件名”,null作为署名,null作为版权,null作为源,null作为“图片标题”,null作为“照片信息”,null作为“alt text”

SELECT fid, MATCH(origname) AGAINST ('search term') AS scoredName, origname, NULL AS N4, NULL AS N5, NULL AS N6, NULL AS N7, NULL AS N8, NULL AS N9
    FROM table1
    WHERE MATCH(origname) AGAINST ('search term')

    UNION

    SELECT entity_id, MATCH(byline) AGAINST ('search term') AS scoredByline, NULL AS N3, byline, NULL AS N5, NULL AS N6, NULL AS N7, NULL AS N8, NULL AS N9
    FROM table2   
    WHERE MATCH (byline) AGAINST ('search term')

    UNION

    SELECT entity_id, MATCH(copyright) AGAINST ('search term') AS scoredCopyright, NULL AS N3, NULL AS N4, copyright, NULL AS N6, NULL AS N7, NULL AS N8, NULL AS N9
    FROM table3
    WHERE MATCH (copyright) AGAINST ('search term')

    UNION

    SELECT entity_id, MATCH(source) AGAINST ('search term') AS scoredSource, NULL AS N3, NULL AS N4, NULL AS N5, source, NULL AS N7, NULL AS N8, NULL AS N9
    FROM table4
    WHERE MATCH (source) AGAINST ('search term')

    UNION

    SELECT entity_id, MATCH(image_title) AGAINST ('search term') AS scoredTitle, NULL AS N3, NULL AS N4, NULL AS N5, NULL AS N6, image_title, NULL AS N8, NULL AS N9
    FROM table5
    WHERE MATCH(image_title) AGAINST ('search term')

    UNION

    SELECT entity_id, MATCH(full_photo_info) AGAINST ('search term') AS scoredPhotoInfo, NULL AS N3, NULL AS N4, NULL AS N5, NULL AS N6, NULL AS N7, full_photo_info, NULL AS N9
    FROM table6
    WHERE MATCH(full_photo_info) AGAINST ('search term')

    UNION

    SELECT entity_id, MATCH(file_image_alt_text) AGAINST ('search term') as scoredaltText, NULL AS N3, NULL AS N4, NULL AS N5, NULL AS N6, NULL AS N7, NULL AS N8, file_image_alt_text
    FROM table7
    WHERE MATCH(file_image_alt_text) AGAINST ('search term')
) AS g
GROUP BY fid, score, origname, byline, copyright, source, "Image title", "Photo info", "Alt text"
ORDER BY score DESC;

解释: UNION 只是将后续查询连接到由第一个查询设置的列中。
因此,它们都必须有相同数量的列,这就是为什么您会看到所有这些列 NULL 价值观。
但是不能有两个同名的列,因此必须分别使用别名 NULL .
下一步,我可能会用更重要的指数乘以一个常数来加权不同的指数。

0pizxfdo

0pizxfdo1#

构建一个表,其目的是执行此类搜索。它将有一个单独的文本列来收集其他各种表中的所有单词,并有一个 JOINing 对他们来说。
结果查询:

SELECT ...
    FROM search_table AS st
    WHERE MATCH (st.txt) AGAINST (... IN BOOLEAN MODE)
    JOIN table1 USING(id)
    JOIN table2 USING(id)  -- or whatever is needed for the JOIN ON
    JOIN table3 USING(id)
    ...;

当然,需要您填充 search_table 无论何时填充任何其他表。但是,如果你删除了一些id,它并不需要你去清理 JOIN 在另一个表中根本找不到行。
这个 txt 会被设置为

INSERT INTO `search_table` (id, txt)
    VALUES (id,
            CONCAT_WS(' ', table1.origname,
                           table2.byline,
                            ... ) );
nuypyhwy

nuypyhwy2#

OR 这使得mysql很难进行优化。使用单独的查询,这些查询与 UNION .
这假设每行只有一行 entity_id 在每个相关表格中。否则,原始查询将返回所有匹配行的叉积,而这只是返回每个表的最大匹配。

SELECT fid, MAX(name) AS name, MAX(byline) AS byline, MAX(copyright) AS copyright, MAX(source) AS source, MAX(image_title) AS image_title, MAX(photo_info) AS photo_info, MAX(alt_text) AS alt_text
    FROM (
    SELECT fid, MATCH(name) AGAINST ('search term') as name, NULL AS byline, NULL AS copyright, NULL AS source, NULL AS image_title, NULL AS photo_info, NULL AS alt_text
    FROM table1
    WHERE MATCH(name) AGAINST ('search term')
    UNION
    SELECT entity_id, NULL, MATCH(byline) AGAINST ('search term'), NULL, NULL, NULL, NULL, NULL
    FROM table2
    WHERE MATCH(byline) AGAINST ('search term')
    UNION
    SELECT entity_id, NULL, NULL, MATCH(copyright) AGAINST ('search term'), NULL, NULL, NULL, NULL
    FROM table3
    WHERE MATCH(copyright) AGAINST ('search term')
    UNION
    SELECT entity_id, NULL, NULL, NULL, MATCH(source) AGAINST ('search term'), NULL, NULL, NULL
    FROM table4
    WHERE MATCH(source) AGAINST ('search term')
    UNION
    SELECT entity_id, NULL, NULL, NULL, NULL, MATCH(image_title) AGAINST ('search term'), NULL, NULL
    FROM table5
    WHERE MATCH(image_title) AGAINST ('search term')
    UNION
    SELECT entity_id, NULL, NULL, NULL, NULL, NULL, MATCH(photo_info) AGAINST ('search term'), NULL
    FROM table6
    WHERE MATCH(photo_info) AGAINST ('search term')
    UNION
    SELECT entity_id, NULL, NULL, NULL, NULL, NULL, NULL, MATCH(alt_text) AGAINST ('search term')
    FROM table7
    WHERE MATCH(alt_text) AGAINST ('search term')
) AS u
GROUP BY fid

相关问题