在Clojure中重构BigQuery输出



我是Clojure的新手,我正试图通过Java互操作与BigQuery (BQ)合作。我在BQ中使用的数据集可以在这里找到(WARNING:链接到CSV文件)。我有以下代码:

(ns bq
(:import (com.google.cloud.bigquery BigQueryOptions QueryJobConfiguration BigQuery BigQueryException BigQuery$JobOption)))
(defn querybq [query]
(let [^BigQuery big-query (.getService (BigQueryOptions/getDefaultInstance))
^QueryJobConfiguration query-config (.build (QueryJobConfiguration/newBuilder query))
results (.query big-query query-config (into-array BigQuery$JobOption []))]
results))
;; Dataset location: https://msi.nga.mil/api/publications/download?type=view&key=16920959/SFH00000/UpdatedPub150.csv
(def res (querybq (str "SELECT * FROM xxxxxxxxxx.wpi_dataset.wpi_table LIMIT 10")))
(defn print-res [args]
(doseq [x (.iterateAll res)]
(let [^String y (.getStringValue (.get x 0))]
(println y))))

首先,我查询BigQuery并将结果赋值给res。然后,我调用print-res,它打印出第一列数据。我有两个问题。

  1. 我使用.getStringValue从第一列获得值,但这一列不一定包含字符串。(事实上,它没有——它包含数字。)如何自动将数据提取为正确的类型?

  2. 这只打印第一列,但我想引用所有列。如果我知道doseqrange有多少列,我相信我可以这样做。我能弄清楚有多少列有没有第二次查询数据库(即,直接从res)?


背景:当我在这里打印输出时,最终我试图提取数据,以便我可以将其放入tech.ml.dataset的数据帧中。


deps.edn

{:deps
{com.google.cloud/google-cloud-bigquery {:mvn/version "2.24.4"}}}

res内容示例

#object[com.google.cloud.bigquery.TableResult 0x63d5874f TableResult{rows=[[FieldValue{attribute=PRIMITIVE, value=12500.0}, FieldValue{attribute=PRIMITIVE, value=B
595 razil NE Coast -- 12470}, FieldValue{attribute=PRIMITIVE, value=Cameta}, FieldValue{attribute=PRIMITIVE, value= }, FieldValue{attribute=PRIMITIVE, value=BR CMA}, F
596 ieldValue{attribute=PRIMITIVE, value=Brazil}, FieldValue{attribute=PRIMITIVE, value=South Atlantic Ocean}, FieldValue{attribute=PRIMITIVE, value= }, FieldValue{att
597 ribute=PRIMITIVE, value=Sailing Directions Pub. 124 (Enroute) - East Coast of South America}, FieldValue{attribute=PRIMITIVE, value=https://msi.geo.nga.mil/api/pub
598 lications/download?key=16694491/SFH00000/Pub124bk.pdf&type=view}, FieldValue{attribute=PRIMITIVE, value= }, FieldValue{attribute=PRIMITIVE, value= }, FieldValue{at
599 tribute=PRIMITIVE, value= }, FieldValue{attribute=PRIMITIVE, value=gen01b}, FieldValue{attribute=PRIMITIVE, value=3.0}, FieldValue{attribute=PRIMITIVE, value=0.0},
600  FieldValue{attribute=PRIMITIVE, value=7.9}, FieldValue{attribute=PRIMITIVE, value=14.0}, FieldValue{attribute=PRIMITIVE, value=0.0}, FieldValue{attribute=PRIMITIV
601 E, value=0.0}, FieldValue{attribute=PRIMITIVE, value=0.0}, FieldValue{attribute=PRIMITIVE, value=0.0}, FieldValue{attribute=PRIMITIVE, value=0.0}...

回答我自己的问题:

  1. 还有一个getValue()函数将字段作为对象返回。
  2. 我可以使用size()函数从模式(或从单个行)获得列数。

对于那些纠结于如何在Clojure中处理BQ查询结果的人来说,这是我想到的(在问题中的代码之上)。

有三个函数实际完成以下工作:1)解析出一行的每个字段(parse-row), 2)从模式中提取列名(column-names),以及3)将前两个函数应用于所有行/列,将结果修补在一起,并将结果转换为Tablecloth数据集(bq-to-dataset)。

(defn parse-row [row]
"Split each FieldValueList into its components"
(let [indices (range (.size row))]
(map #(.getValue (.get row %1)), indices)))
(defn column-names [table-result]
"Get column names from TableResult"
(let [field-list (.getFields (.getSchema table-result))
list-length (.size field-list)
list-indices (range list-length)]
(map #(.getName (.get field-list %1)) list-indices)))
(defn bq-to-dataset [table-result]
"Convert a TableResult into a TMD dataset"
(let [cols (map keyword (column-names table-result))]
(->> table-result
(.iterateAll)
(map parse-row)
(map #(zipmap (partial cols) %1))
(tc/dataset))))

为了演示这一点,我们可以提取一些列,然后打印它们。

(defn -main [& args]
(-> (bq-to-dataset res)
(tc/select-columns [:MainPortName :RegionName :WorldPortIndexNumber])
(print)))
| :MainPortName |                 :RegionName | :WorldPortIndexNumber |                                                                                                     
|---------------|-----------------------------|-----------------------|                                                                                                     
|       Deering |   Alaska Continued -- 20185 |               20430.0 |                                                                                                     
|      Manistee |    US Lake Michigan -- 4570 |                4650.0 |                                                                                                     
|   Great Lakes |    US Lake Michigan -- 4570 |                4820.0 |                                                                                                     
|        Oconto |    US Lake Michigan -- 4570 |                5010.0 |                                                                                                     
|   Blind River |   Canada Lake Huron -- 3640 |                4200.0 |                                                                                                     
|  Presque Isle |    US Lake Superior -- 5230 |                5290.0 |                                                                                                     
|     Marquette |    US Lake Superior -- 5230 |                5280.0 |                                                                                                     
|      Wilmette |    US Lake Michigan -- 4570 |                4810.0 |                                                                                                     
|      Oakville | Canada Lake Ontario -- 2820 |                3020.0 |                                                                                                     
|    Belleville | Canada Lake Ontario -- 2820 |                2930.0 |   

相关内容

  • 没有找到相关文章

最新更新