【问题标题】:BigQuery / DataPrep: Efficient way to extract word counts; to convert HTML to plaintextBigQuery / DataPrep:提取字数的有效方法;将 HTML 转换为纯文本
【发布时间】: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

一种方法是这样的:

  1. {alphanum-underscore}+ 的文档摘录列表 id, wordlist 1, ["foo", "bar", "foo", "baz"] 2, ["foo", "bar", "bar", "qux"]
  2. 扁平化词表 id, word 1, foo 1, bar 1, foo 1, baz 2, foo 2, bar 2, bar 2, qux
  3. 按组聚合: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。

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

【问题讨论】:

    标签: google-bigquery google-cloud-dataflow tf-idf google-cloud-dataprep


    【解决方案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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-04-12
      • 2014-09-08
      • 1970-01-01
      • 2014-07-20
      • 2018-03-17
      • 1970-01-01
      • 2014-04-21
      相关资源
      最近更新 更多