【问题标题】:Improve BigQuery case insensitive search performance提高 BigQuery 不区分大小写的搜索性能
【发布时间】:2018-01-24 07:13:30
【问题描述】:

BigQuery 团队再次出击:这个问题不再相关,因为现在使用 LOWER() 的结果与使用 REGEX() 的结果一样快。


使用 BigQuery 处理大约 5GB 的数据应该非常快。例如,以下查询在 18 秒内执行不区分大小写的搜索:

#standardSQL
SELECT COUNT(*) c
FROM `bigquery-public-data.hacker_news.full` 
WHERE 
  LOWER(text) LIKE '%bigquery%' # 18s

通常 BigQuery 比这更快,但真正的问题是添加新的搜索词会使这个查询变得相当慢(几乎一分钟,有 3 个搜索词):

#standardSQL
SELECT COUNT(*) c
FROM `bigquery-public-data.hacker_news.full` 
WHERE 
  LOWER(text) LIKE '%bigquery%' OR LOWER(text) LIKE '%big query%' # 34s

#standardSQL
SELECT COUNT(*) c
FROM `bigquery-public-data.hacker_news.full` 
WHERE 
  LOWER(text) LIKE '%bigquery%' OR LOWER(text) LIKE '%big query%'
  OR LOWER(text) LIKE '%google cloud%' # 52s

如何提高查询性能?

【问题讨论】:

    标签: performance google-bigquery


    【解决方案1】:

    团队注意事项:敬请期待!很快 BigQuery 将把它变成 建议无关紧要。

    BigQuery 性能提示:避免使用 LOWER() 和 UPPER()

    LOWER() 和 UPPER() 操作在处理 Unicode 文本时会遇到困难:每个字符都需要单独映射,它们也可以是多字节。

    解决方案 1:不区分大小写的正则表达式

    更快的选择:使用REGEX_MATCH() 并将不区分大小写的(?i) 修饰符添加到您的正则表达式中

    #standardSQL
    SELECT COUNT(*) c
    FROM `bigquery-public-data.hacker_news.full` 
    WHERE 
       REGEXP_CONTAINS(text, '(?i)bigquery') # 7s
    
    #  REGEXP_CONTAINS(text, '(?i)bigquery')
    #   OR REGEXP_CONTAINS(text, '(?i)big query') # 9s
    
    #  REGEXP_CONTAINS(text, '(?i)bigquery') 
    #   OR REGEXP_CONTAINS(text, '(?i)big query') 
    #   OR REGEXP_CONTAINS(text, '(?i)google cloud') # 11s
    

    这样性能会好很多:

    • 1 个搜索词:18s 到 8s
    • 2 个搜索词:34 秒到 9 秒
    • 3 个搜索词:52 秒到 11 秒。

    解决方案 2:组合正则表达式

    当一个正则表达式可以将多个组合为 1 时,为什么要进行 3 次搜索?

    #standardSQL
    SELECT COUNT(*) c
    FROM `bigquery-public-data.hacker_news.full` 
    WHERE 
      REGEXP_CONTAINS(text, '(?i)(bigquery|big query|google cloud)') # 7s
    

    3 个词在 7 秒内 - 不错。

    解决方案 3:转换为字节

    这更难看,但表明 UPPER() 和 LOWER() 在处理单个字节时表现得更好 - 在这些搜索中获得相同的结果:

    #standardSQL
    SELECT COUNT(*) c
    FROM `bigquery-public-data.hacker_news.full` 
    WHERE 
      LOWER(CAST(text AS BYTES)) LIKE b'%bigquery%'
      OR LOWER(CAST(text AS BYTES)) LIKE b'%big query%' 
      OR LOWER(CAST(text AS BYTES)) LIKE b'%google cloud%' # 7s
    

    LOWER() 比较慢。请改用正则表达式 (?i) 修饰符。

    如果这对您有用,请随时评论您的性能改进。

    【讨论】:

    • 感谢 Elliot Brossard 的提示!
    • 更短的解决方案 2(类似性能):REGEXP_CONTAINS(text, '(?i)(big( )?query|google cloud)')
    • 是的 - 但只是因为我为这个例子选择了类似的字符串:)
    猜你喜欢
    • 2016-08-03
    • 2012-01-31
    • 2017-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-15
    • 2011-11-20
    • 1970-01-01
    相关资源
    最近更新 更多