mysql中文件路径搜索的改进
我需要搜索数百万个文件名。它们看起来像这样:mysql中文件路径搜索的改进,mysql,sql,unix,search,full-text-search,Mysql,Sql,Unix,Search,Full Text Search,我需要搜索数百万个文件名。它们看起来像这样: LG_MARGINCALL_HD2CH_127879834_EN.mov 如果有人搜索以下任一项,则应匹配: 边际 追加保证金通知 追加保证金通知 追加保证金 追加保证金通知 我目前使用的是mysql%类%搜索。比如: SELECT filename FROM path WHERE filename LIKE '%margin%' AND filename LIKE '%mov%' SELECT filename FROM path WHER
LG_MARGINCALL_HD2CH_127879834_EN.mov
如果有人搜索以下任一项,则应匹配:
- 边际
- 追加保证金通知
- 追加保证金通知
- 追加保证金
- 追加保证金通知
SELECT filename FROM path WHERE filename LIKE '%margin%' AND filename LIKE '%mov%'
SELECT filename FROM path WHERE MATCH(filename) AGAINST('+margin +call +hd +en +mov' IN BOOLEAN MODE);
它的速度非常慢(搜索最多需要10秒钟)。请注意,它确实起作用
进行上述搜索的更好方法是什么?使用mysql或其他程序。您注意到,您的搜索策略很慢。速度慢是因为
LIKE '%something%'
必须扫描表才能找到匹配项。在像搜索这样的搜索中领先%的符号是破坏性能的一种极好的方法
我不知道您的path
表中有多少列。如果有很多列,您可以做两件快速的事情来提高性能:
摆脱选择*
,并在结果集中列出所需列的名称
创建一个复合索引,由filename
列组成,后跟需要检索的其他列
(如果您的表中只有几列,这将没有帮助。)
您不能直接使用软件包FULLTEXT
搜索这些内容,因为这是为语言文本设计的
如果我必须使这项工作快速投入生产,我会这样做:
首先,创建一个名为“searchterm”的新表,其中包含
filename_id INT the id number of a row in your path table
searchterm VARCHAR(20) a fragment of a filename.
其次,编写一个程序,读取filename\u id
和filename
值,并在searchterm
中插入一组不同的行。对于已显示的项目,值应为:
LG_MARGINCALL_HD2CH_127879834_EN.mov (original)
LG MARGINCALL HD2CH 127879834 EN mov (split on punctuation)
HD 2 CH (split on embedded numerics)
MARGIN CALL (split on an app-specific list of words)
因此,您的searchterm表中有一组条目,所有条目都具有相同的filename\u id
值和大量不同的小文本块
最后,在搜索时,您可以这样做
SELECT path.id, path.filename, path.whatever,
COUNT(DISTINCT searchterms.term) AS termcount
FROM path
JOIN searchterm ON path.filenanme_id = search.filename_id
WHERE searchterm.term IN ('margin','call','hd','en', 'mov')
GROUP BY path.id, path.filename, path.whatever
ORDER BY path.filename, COUNT(DISTINCT searchterms.term) DESC
这个小查询会找到与您搜索的内容相匹配的所有片段。它返回多个文件名,并按与大多数术语匹配的顺序显示它们
我建议您创建自己的特定于应用程序的排序全文搜索系统。如果你真的有几百万个多媒体文件,这肯定值得你付出努力。停止使用like语句,改用match()并为搜索列使用全文索引,你的表必须是MYISAM表(我不知道是否是)我建议尝试两种方法以获得更好的性能。第一种方法是在选择之前使用关键字。这可能会对查询的缓慢性能提供一些帮助。但我认为这不会有多大帮助。第二件事是使用。所有这些的一个例子:
EXPLAIN SELECT filename FROM path WHERE filename LIKE REGEXP '^.*MAR{1}.*mov{1}'
但是您必须再搜索一点来优化正则表达式。尝试使用SPHINX进行全文搜索。
这可能比使用和更快:
SELECT filename FROM path WHERE filename LIKE '%margin%call%hd%en%mov%'
但是在字符串的开头有一个“%”总是会使它变慢
您应该在字段上使用全文搜索索引,然后使用以下内容:
SELECT filename FROM path WHERE filename LIKE '%margin%' AND filename LIKE '%mov%'
SELECT filename FROM path WHERE MATCH(filename) AGAINST('+margin +call +hd +en +mov' IN BOOLEAN MODE);
显然,您需要全文搜索功能
有多种解决方案可以应对这一问题,目前最好的解决方案之一是
它具有处理实时全文搜索的所有功能。
它提供了自动建议、自动完成等功能,大大超出了这一范围
而且它是开源的。谢谢你的回答。我喜欢上面的想法,但我很难弄清楚我们将如何进行“特定于应用程序”的关键字拆分,例如电影标题:margincall-->margincall。我们并不真正知道基于文件的所有电影名称(通常可能是缩写的)。在任何Linux或*nix发行版中,都有一个免费的(像小猫一样免费,像说话一样免费)文件,里面充满了常见的单词。看见你也许可以用这个文件来帮助分解像MARGINCALL这样的短语。谢谢,这很有帮助,我认为这对英文标题很有用。外国头衔呢?例如:ABRESUSOJOS_HD.mov()。一些可能的来源:我认为这些比英文单词表要难用一点。@user1436531,因为外国标题很难破译成单词,而且事情因变音符号(é,ü…->e,ue…)和连字(æ,ß…,ae,ss…)而变得复杂,这可能会“标准化为英语”用户是否会按文件名、电影名称或两者进行搜索?他们将同时搜索这两种内容。我建议您看看Lucene,它非常适合此类搜索。听起来像是一种新的bittorrent服务:)