在 BigQuery 中使用 javascript udf 进行 tf idf 计算时,UDF 工作程序在执行期间超时

Posted

技术标签:

【中文标题】在 BigQuery 中使用 javascript udf 进行 tf idf 计算时,UDF 工作程序在执行期间超时【英文标题】:UDF worker timed out during execution when using javascript udf in BigQuery for tf idf calculation 【发布时间】:2019-07-30 05:17:10 【问题描述】:

我尝试在 BigQuery 中实现一个查询,该查询使用 tf-idf 分数从更大的文档集合中查找文档的热门关键字。

在计算关键字的 tf-idf 分数之前,我清理文档(例如删除停用词和标点符号),然后从文档中创建 1、2、3 和 4-gram,然后在 n-克。

为了执行这种清理、n-gram 创建和词干提取,我使用了 javascript 库和 js udf。这是示例查询:

CREATE TEMP FUNCTION nlp_compromise_tokens(str STRING)
RETURNS ARRAY<STRUCT<ngram STRING, count INT64>> LANGUAGE js AS '''
  // creating 1,2,3 and 4 grams using compormise js
  // before that I remove stopwords using .removeStopWords
  // function lent from remove_stop_words.js
  tokens_from_compromise = nlp(str.removeStopWords()).normalize().ngrams(max:4).data()

  // The stemming function that stems
  // each space separated tokens inside the n-grams
  // I use snowball.babel.js here
  function stems_from_space_separated_string(tokens_string) 
    var stem = snowballFactory.newStemmer('english').stem;
    splitted_tokens = tokens_string.split(" ");
    splitted_stems = splitted_tokens.map(x => stem(x));
    return splitted_stems.join(" ")
  

  // Returning the n-grams from compromise which are 
  // stemmed internally and at least length of 2
  // alongside the count of the token inside the document
  var ngram_count = tokens_from_compromise.map(function(item) 
    return 
      ngram: stems_from_space_separated_string(item.normal),
      count: item.count
    ;
  );
  return ngram_count
'''
OPTIONS (
  library=["gs://fh-bigquery/js/compromise.min.11.14.0.js","gs://syed_mag/js/snowball.babel.js","gs://syed_mag/js/remove_stop_words.js"]);

with doc_table as (
  SELECT 1 id, "A quick brown 20 fox fox fox jumped over the lazy-dog" doc UNION ALL
  SELECT 2, "another 23rd quicker browner fox jumping over Lazier broken! dogs." UNION ALL
  SELECT 3, "This dog is more than two-feet away." #UNION ALL
),
  ngram_table as(
  select
    id,
    doc,
    nlp_compromise_tokens(doc) as compromise_tokens
  from
    doc_table),
n_docs_table as (
  select count(*) as n_docs from ngram_table
),
df_table as (
SELECT
  compromise_token.ngram,
  count(*) as df
FROM
  ngram_table, UNNEST(compromise_tokens) as compromise_token
GROUP BY
  ngram
),

idf_table as(
SELECT
  ngram,
  df,
  n_docs,
  LN((1+n_docs)/(1+df)) + 1 as idf_smooth
FROM
  df_table
CROSS JOIN
  n_docs_table),

tf_idf_table as (  
SELECT
  id,
  doc,
  compromise_token.ngram,
  compromise_token.count as tf,
  idf_table.ngram as idf_ngram,
  idf_table.idf_smooth,
  compromise_token.count * idf_table.idf_smooth as tf_idf
FROM
  ngram_table, UNNEST(compromise_tokens) as compromise_token
JOIN
  idf_table
ON
  compromise_token.ngram = idf_table.ngram)

SELECT
  id,
  ARRAY_AGG(STRUCT(ngram,tf_idf)) as top_keyword,
  doc
FROM(
  SELECT
    id,
    doc,
    ngram,
    tf_idf,
    ROW_NUMBER() OVER (PARTITION BY id ORDER BY tf_idf DESC) AS rn
  FROM
    tf_idf_table)
WHERE
  rn < 5
group by
  id,
  doc

示例输出如下所示:

在此示例中只有三个示例手工行。

当我尝试使用具有 1000 行的稍大一点的表执行相同的代码时,它再次运行良好,尽管需要更长的时间才能完成(仅 1000 行大约需要 6 分钟)。此示例表 (1MB) 可以是 json 格式的found here。

现在,当我在 a larger dataset (159K rows - 155MB) 上尝试查询时,查询在大约 30 分钟后耗尽,并显示以下消息:

错误:用户定义函数:UDF worker 在执行期间超时。 为 worker worker-109498 触发了意外中止:job_timeout (错误代码:超时)

我能否改进我的 udf 函数或整体查询结构,以确保它在更大的数据集(124,783,298 行 - 244GB)上平稳运行?

注意我已经对 google 存储中的 js 文件给予了适当的许可,以便任何人都可以访问这些 javascrip 来运行示例查询。

【问题讨论】:

【参考方案1】:

BigQuery UDF 非常方便,但计算量不大,不会让您的查询变慢或耗尽资源。有关限制和最佳实践,请参阅 doc reference。一般来说,您可以在本机 SQL 中转换的任何 UDF 逻辑都将更快并且使用更少的资源。

我会将您的分析分成多个步骤,将结果保存到每个步骤的新表中:

    清理文档(例如删除停用词和标点符号) 从文档中创建 1、2、3 和 4-gram,然后在 n-gram 内进行词干提取。 计算分数。

旁注:您可以使用多个 CTE 运行它来保存阶段,而不是将每个步骤保存到本机表中,但我不知道这是否会使查询超出资源限制。

【讨论】:

以上是关于在 BigQuery 中使用 javascript udf 进行 tf idf 计算时,UDF 工作程序在执行期间超时的主要内容,如果未能解决你的问题,请参考以下文章

如何为 Google BigQuery 转义 JavaScript UDF 中的字符?

BigQuery JavaScript UDF 使用 SQL 查询中的值调用数组

用于 BigQuery UDF 的纯 javascript HTML 解析器

BigQuery JavaScript UDF:V8 实例的区域

有没有办法从 javascript 调用 bigquery API 函数?

使用 JavaScript BigQuery UDF 解密/解码 AES256 [重复]