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
如果有人搜索以下任一项,则应匹配:

  • 边际
  • 追加保证金通知
  • 追加保证金通知
  • 追加保证金
  • 追加保证金通知
我目前使用的是mysql%类%搜索。比如:

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服务:)