代码之家  ›  专栏  ›  技术社区  ›  Chuck Burgess

大数据集的流程优化

  •  2
  • Chuck Burgess  · 技术社区  · 14 年前

    我目前有一个项目,我们正在处理3千万以上的PPC广告关键字。我们在甲骨文中维护这些列表。有时我们需要从列表中删除某些关键字。该过程包括各种匹配类型策略,以确定是否应删除关键字:

    • 准确的 : WHERE keyword = '{term}'
    • : WHERE keyword LIKE '%{term}%'
    • 代币 WHERE keyword LIKE '% {term} %' OR keyword LIKE '{term} %' OR keyword LIKE '% {term}'

    现在,处理列表时,它只能使用上面列出的匹配类型之一。但是,必须扫描所有30mil+关键字以查找匹配项,并返回匹配项的结果。目前,根据要搜索的关键字列表中的关键字数,此过程可能需要数小时/天的时间来处理。

    您对如何优化流程以使其运行更快有什么建议吗?

    更新: 下面是一个用于搜索假日酒店的查询示例:

    SELECT * FROM keyword_list 
    WHERE
    (
    lower(text) LIKE 'holiday inn' OR
    lower(text) LIKE '% holiday inn %' OR
    lower(text) LIKE 'holiday inn %'
    );
    

    http://pastebin.com/tk74uhP4

    一些可能有用的附加信息。关键字可以由多个单词组成,例如:

    • 这是一个示例关键字
    • 我喜欢我的关键词
    7 回复  |  直到 14 年前
        1
  •  3
  •   Hynek -Pichi- Vychodil Paulo Suassuna    14 年前

    根据我的经验,perl能够以每秒数百万的速度进行regexp扫描。我不知道你从数据库中转储的速度有多快(MySQL可以达到200krows/s,所以你可以在2.5分钟内转储所有关键字,我知道Oracle在这里要差得多,但我希望不会超过10倍,即25分钟)。如果您的数据平均为20个字符,则转储为600MB,100个字符则为3GB。这意味着,使用慢速100MB/s高清,IO将从6秒变为30秒。(所有涉及的IO都是连续的!)与perl中的转储和处理时间相比,这几乎是微不足道的。你的扫描速度可以减慢到100k/s,这取决于你想删除的关键字的数量(我曾经体验过regexp以这种速度有500个分支模式),所以你可以在不到5分钟的时间内处理结果数据。如果产生的基数不会很大(成百上千),输出IO应该不会有问题。不管怎样,你的处理应该在几分钟内完成,而不是几个小时。如果生成整个关键字值进行删除,则可以在删除操作中使用索引,因此将生成一系列 DELETE FROM <table> WHERE keyword IN (...) 塞满了要删除的关键字,最多可删除SQL语句的最大长度。您还可以尝试将此数据上载到临时表,然后使用join。我不知道在甲骨文里什么会更快。在MySQL中大约需要10分钟。你是不幸的,你必须处理与甲骨文,但你应该能够删除数百个 {term}

    另外:我建议你使用一些更好的正则表达式,比如 http://code.google.com/p/re2/

        2
  •  5
  •   DVK    14 年前

    千万不要使用以“%”开头的LIKE匹配o大数据集-它不能在该字段上使用表索引,并且将执行表扫描。这是你行动迟缓的根源。

    keyword LIKE '{term} %' ).

    要解决此问题,请创建一个新的索引表(不要与数据库的表索引混淆),将各个术语映射到包含这些术语的关键字字符串;然后 keyword LIKE '% {term} %' 变成 t1.keyword = index_table.keyword and index_table.term="{term}" .

        3
  •  2
  •   Bob Jarvis - Слава Україні    14 年前

    我认为问题是如何存储关键字。如果我正确地解释了您的代码,那么KEYWORD列由一串空格分隔的关键字值组成,例如

    KEYWORD1 KEYWORD2 KEYWORD3
    

    正因为如此,你不得不用LIKE来做搜索,而这可能就是搜索速度慢的原因。

    虽然我意识到这可能有点痛苦,但最好创建第二个表,可能称为关键字,它将包含与给定基表记录相关的各个关键字(我将基表称为PPC,因为我不知道它真正的名称)。假设当前基表如下所示:

    CREATE TABLE PPC
     (ID_PPC       NUMBER PRIMARY KEY,
      KEYWORD      VARCHAR2(1000),
      <other fields>...);
    

    您可以按如下方式重新生成表:

    CREATE TABLE NEW_PPC
     (ID_PPC       NUMBER PRIMARY KEY,
      <other fields>...);
    
    CREATE TABLE NEW_PPC_KEYWORD
     (ID_NEW_PPC       NUMBER,
      KEYWORD      VARCHAR2(25),  -- or whatever is appropriate for a single keyword
      PRIMARY KEY (ID_NEW_PPC, KEYWORD));
    
    CREATE INDEX NEW_PPC_KEYWORD_1
      ON NEW_PPC_KEYWORD(KEYWORD);
    

    您可以通过从旧关键字表中提取单个关键字来填充新的\u PPC\u关键字表PPC.关键字字段,将它们放入新的\u PPC\u关键字表中。由于NEW\u PPC\u keyword中的每个记录中只有一个关键字,您现在可以使用一个简单的连接来拉取NEW\u PPC中所有有关键字的记录,方法如下

    SELECT P.*
      FROM NEW_PPC P
    INNER JOIN NEW_PPC_KEYWORD K
      ON (K.ID_NEW_PPC = P.ID_NEW_PPC)
    WHERE K.KEYWORD = '<whatever>';
    

        4
  •  2
  •   Community T.Woody    7 年前

    这些信息不足以给出任何具体的建议。如果价格昂贵 LIKE 匹配是不可避免的,那么我现在唯一看到的是:


    更新


    select AD.id
    from DICT, AD
    where 
      DICT.word = :input_word and
      DICT.word_id = AD.word_id
    

    DICT 是一张有单词和单词的桌子 AD keyword_list

    从本质上讲,人们可以把你遇到的问题概括为 "full table scan" . 这是一个非常常见的问题,通常会突出数据布局的糟糕设计。在网上搜索更多关于可以做什么的信息。 SO has many entries too .

        5
  •  2
  •   Jon Heller TenG    14 年前

    你的解释计划说这个查询需要一分钟,但实际上需要几个小时?在我的家用电脑上进行的一个简单测试验证了一分钟对于这个查询似乎是合理的。在一个有一些不错的IO的服务器上,这可能只需要几秒钟。

    问题是,对于不同的关键字,同一个查询要连续运行几十次吗?如果是这样,则需要将所有搜索组合在一起,以便只扫描表一次。

        6
  •  1
  •   Dave Costa    14 年前

    你可以看看 Oracle Text

        7
  •  1
  •   Dave    13 年前

    我的建议是将cach大小提高到数百gb。向它扔硬件。如果你不能建立一个贝奥武夫集群或建立一个二进制空间搜索引擎。