BigQuery / DataPrep:提取字数的有效方法;将 HTML 转换为纯文本

Posted

技术标签:

【中文标题】BigQuery / DataPrep:提取字数的有效方法;将 HTML 转换为纯文本【英文标题】:BigQuery / DataPrep: Efficient way to extract word counts; to convert HTML to plaintext 【发布时间】:2017-10-09 11:06:46 【问题描述】:

我有一个存储在 BigQuery 中的约 470 万个文档的表。有些是纯文本,有些是 html。它们大约有 2k 个令牌,变化很大。我主要使用 DataPrep 进行处理。

我想提取这些标记并计算 TF-IDF 值。

令牌计数

其中一个更耗时的步骤是:

id, document
1, "foo bar foo baz"
2, "foo bar bar qux"

然后把它变成这样:

id, word, count
1, foo, 2
1, bar, 1
1, baz, 1
2, foo, 1
2, bar, 2
2, qux, 1

一种方法是这样的:

    alphanum-underscore+ 的文档摘录列表 id, wordlist 1, ["foo", "bar", "foo", "baz"] 2, ["foo", "bar", "bar", "qux"] 扁平化词表 id, word 1, foo 1, bar 1, foo 1, baz 2, foo 2, bar 2, bar 2, qux 按组聚合:id、word、值:count() id, word, count 1, foo, 2 1, bar, 1 1, baz, 1 2, foo, 1 2, bar, 2 2, qux, 1

但是,第 2 步和第 3 步非常慢,尤其是对于大型文档。

理想情况下,我应该能够拥有一个将["foo", "bar", "foo", "baz"] 转换为"foo":2, "bar":1, "baz":1 的函数。这不需要 flatten-then-group 操作来提取计数,并且随后的 flatten 会更小(因为它在唯一的术语而不是每个术语上运行)。

但是,我还没有想出在 DataPrep 中执行此操作的任何方法。 :-/

有什么更有效的方法来做到这一点?

HTML 转纯文本

我的源数据是纯文本和 html 的组合。在 370 万份文档中,只有大约 80 万份有明文可用。

我想以某种合理的方式将 html 转换为纯文本(例如,相当于 Nokogiri #content),这样我就可以对结果进行令牌提取。

我可以启动一个执行 bq query 的集群,摄取 html,使用 nokogiri 处理它,然后将其输出到处理过的表中。但这有点复杂,需要大量的 i/o。

有没有更简单/更有效的方法来做到这一点?

【问题讨论】:

【参考方案1】:

我认为您可以在 BigQuery 中完成所有操作 下面应该给你一个好的开始 在每个文档和整个语料库中都有词频 并且 html 以及只是数字的单词都被删除了 您现在可以在此处添加任何额外的处理,包括 TF-IDF

#standardSQL
WITH removed_html AS (
  SELECT id, REGEXP_REPLACE(document, r'<[^>]*>', ' ') AS document
  FROM `yourTable`
),
words_in_documents AS (
  SELECT id, 
    ARRAY(
      SELECT AS STRUCT word, COUNT(1) AS cnt 
      FROM UNNEST(REGEXP_EXTRACT_ALL(document, r'[\w_]+')) AS word 
      GROUP BY word
      HAVING NOT REGEXP_CONTAINS(word, r'^\d+$')
    ) AS words
  FROM removed_html
),
words_in_corpus AS (
  SELECT word, SUM(cnt) AS cnt
  FROM words_in_documents, UNNEST(words) AS words
  GROUP BY word
)
SELECT * 
FROM words_in_corpus

您可以使用问题中的虚拟数据来测试/玩这个

#standardSQL
WITH `yourTable` AS (
  SELECT 1 AS id, "foo bar, foo baz" AS document UNION ALL
  SELECT 2, "foo bar bar qux" UNION ALL
  SELECT 3, '''
<h5 id="last_value">LAST_VALUE</h5>
<pre class="codehilite"><code>LAST_VALUE (value_expression [RESPECT | IGNORE NULLS])</code></pre>
  '''
),
removed_html AS (
  SELECT id, REGEXP_REPLACE(document, r'<[^>]*>', ' ') AS document
  FROM `yourTable`
),
words_in_documents AS (
  SELECT id, 
    ARRAY(
      SELECT AS STRUCT word, COUNT(1) AS cnt 
      FROM UNNEST(REGEXP_EXTRACT_ALL(document, r'[\w_]+')) AS word 
      GROUP BY word
      HAVING NOT REGEXP_CONTAINS(word, r'^\d+$')
    ) AS words
  FROM removed_html
),
words_in_corpus AS (
  SELECT word, SUM(cnt) AS cnt
  FROM words_in_documents, UNNEST(words) AS words
  GROUP BY word
)
SELECT * 
FROM words_in_corpus
ORDER BY cnt DESC

【讨论】:

以上是关于BigQuery / DataPrep:提取字数的有效方法;将 HTML 转换为纯文本的主要内容,如果未能解决你的问题,请参考以下文章

将数据集参数添加到列中,以便稍后通过 DataPrep 在 BigQuery 中使用它们

BigQuery 表的架构与配方不匹配

在 Google Dataprep 中将字符串转换为数组

按最新日期过滤 BigQuery 行的最有效方法

如何在 GCP 中运行自己的学习算法?

导出的数据流模板参数未知