中野智文のブログ

データ・マエショリストのメモ

gsutil compose で 32より多いファイルを結合したいとき

背景

gsutil compose はファイルを結合する便利コマンド。しかし32より多いファイルは結合できない。

解決策

xargs -L31 を使う。

 echo -n | gsutil cp - gs://your-bucket/total.gz
 gsutil ls gs://your-bucket/your_file*.gz | xargs -L31 | xargs -I{} echo gsutil compose gs://your-bucket/total.gz {} gs://your-bucket/total.gz | sh

ここで、your-bucketバケット、total.gz はコピー先、your_file*.gz はコピー元を示す。

詳細

本当は xargs を一つにまとめたかったのだが、-I オプション(リプレイス)を使うと、強制的に -L31-L1 に変更されてしまうので、こうなった。 また echo ... | sh になっているのは、リプレイス先がスペースを含んだ複数のファイルが一つのファイルと認識されてしまうため。

Cloud Firestore は、オブジェクトをサポートされているデータ型に変換します。

background

firestore からデータを取得する良い方法を探して公式ドキュメントを眺める。

firebase.google.com

すると、

一部の言語では、カスタムのオブジェクト タイプを使用する方が便利な場合が多くあります。

と書いてあるではないか?

doc_ref = db.collection(u'cities').document(u'BJ')

doc = doc_ref.get()
city = City.from_dict(doc.to_dict())
print(city)

Cityというカスタムのオブジェクトタイプに戻すのか。pythonはどうやらfrom_dict関数によってサポートされているらしい。

カスタムのオブジェクトタイプとは?

どうやらデータの追加のセクションにあるらしい。

firebase.google.com

つぎのような心強いお言葉が。

Cloud Firestore では、カスタムクラスを使ったドキュメント作成をサポートしています。
Cloud Firestore は、オブジェクトをサポートされているデータ型に変換します。

Webのサンプルコードは次の様。

class City(object):
    def __init__(self, name, state, country, capital=False, population=0,
                 regions=[]):
        self.name = name
        self.state = state
        self.country = country
        self.capital = capital
        self.population = population
        self.regions = regions

    @staticmethod
    def from_dict(source):
        # ...

    def to_dict(self):
        # ...

    def __repr__(self):
        return(
            f'City(\
                name={self.name}, \
                country={self.country}, \
                population={self.population}, \
                capital={self.capital}, \
                regions={self.regions}\
            )'
        )

肝心な from_dict クラスは省略されている。このカスタムオブジェクトクラスも、単なる objectクラスから作られていない?

Cloud Firestore は、オブジェクトをサポートされているデータ型に変換します。

ってどういう意味だろう。日本語の翻訳誤りかな。英語で見てみると、

Cloud Firestore converts the objects to supported data types.

誤りはなさそうだ。。。だが、何もサポートされていないじゃないかな…。一応コードを見てみる。

github.com

全部自前でやってるじゃないか。どこにもライブラリでなんとかしている箇所がない。

まとめ

Cloud Firestore は、オブジェクトをサポートされているデータ型に変換しません。 ご自分で頑張って下さい。

BQで地域メッシュコード(2分の1)のポリゴン

背景

BQで地域メッシュコード(2分の1)からポリゴンを作ることになった。

クエリ

とはいっても、ほとんど temp function ですが。

create temp function INT(S STRING) AS (CAST(S AS INT64));
create temp function STR(F FLOAT64) AS (CAST(F AS STRING));
create temp function FINT(F FLOAT64) AS (CAST(F-0.5 AS INT64));
create temp function SS1(CODE STRING, POS INT64) AS ( INT(SUBSTR(CODE, POS+1, 1))); 
create temp function SS2(CODE STRING, POS INT64) AS ( INT(SUBSTR(CODE, POS+1, 2))); 
create temp function LA4(CODE STRING) AS (FINT((SS2(CODE, 8)-1)/2));
create temp function LAT4(CODE STRING, I INT64) AS ((SS2(CODE, 0)+(SS1(CODE, 4)+(SS1(CODE, 6)+(LA4(CODE)+I)/2)/10)/8)/1.5);
create temp function LAT40(CODE STRING) AS (STR(LAT4(CODE, 0)));
create temp function LAT41(CODE STRING) AS (STR(LAT4(CODE, 1)));
create temp function LO4(CODE STRING) AS (FINT(MOD((SS2(CODE, 8)-1), 2)));
create temp function LON4(CODE STRING, I INT64) AS (SS2(CODE, 2)+100+(SS1(CODE, 5)+(SS1(CODE, 7)+(LO4(CODE)+I)/2)/10)/8);
create temp function LON40(CODE STRING) AS (STR(LON4(CODE, 0)));
create temp function LON41(CODE STRING) AS (STR(LON4(CODE, 1)));
create temp function WKT4(CODE STRING) AS ("POLYGON((" || LON40(CODE) || " " || LAT40(CODE) || ", " || LON41(CODE) || " " || LAT40(CODE) || ", " || LON41(CODE) || " " || LAT41(CODE) || ", " || LON40(CODE) || " " || LAT41(CODE) || ", " || LON40(CODE) || " " || LAT40(CODE) || "))" );

select ST_GEOGFROMTEXT(WKT4("533946113")) AS geog

まとめ

とりあえず、できた。エラーチェックなどはないので、偉い人は自分でつくろう。

参考文献

https://www.stat.go.jp/data/mesh/pdf/gaiyo1.pdf

Azure Storage Blob に python で、stream upload

背景

Azure Storage Blobにpython で、stream upload したので、メモ。

こうした

Azure 自体触ったことないので、よくわからないが、

from azure.storage.blob import BlobServiceClient

というライブラリを使った方法(レガシーなライブラリも存在するらしい)。 詳しくは、ここを参照。

    blob_service_client = BlobServiceClient(account_url=AZURE_STORAGE_ACCOUNT_STRING)
    blob_client = blob_service_client.get_blob_client(container=CONTAINER_NAME, blob=BLOB_NAME)
    blob_client.upload_blob(sys.stdin.buffer, length=length)

ここで、AZURE_STORAGE_ACCOUNT_STRINGは、然るべき方法で取得した文字列(実は知らない)。 CONTAINER_NAMEはコンテナ名の文字列、BLOB_NAME はblobの文字列。 sys.stdin.buffer は標準入力のバイナリ。 大切なのは、length 。これがないと、エラー。 ストリームなのに、サイズが分かってないとダメ。これは仕様(書いてないけど)としては厳しいなあ…

まとめ

stream upload したければ、サイズを先に調べて、lengthに渡す。

リポジトリに接続できませんでした cloud source repositories

背景

Cloud Build 使おうと思ったけど、github のprivate repositories を使うのは、Cloud KMSなどのサービス使うから嫌だなあと思っていたら、

GitHub リポジトリのミラーリング  |  Cloud Source Repositories のドキュメント  |  Google Cloud

という方法もあってそれをやろうとしたら、

f:id:nakano-tomofumi:20200223224925p:plain
リポジトリに接続できませんでした

解決策

Cloud Source Repositories にとりあえず、空でいいのでレポジトリを一つ作る。

リポジトリの作成はこちらから https://source.cloud.google.com/repos?hl=ja

BigQuery で最大最小が overlap しているものをまとめる(その最大最小を得る)

背景

最小と最大のペアの集合があるとする。

例えば、[最小, 最大]とすると、

[1, 2], [3, 4], [4, 5], [6, 7], [6, 8], [9, 10]

というような集合。

[3, 4], [4, 5]

は、まとめて、

[3, 5]

にしたい。

他にも、

[6, 7], [6, 8]

も、まとめて、

[6, 8]

にしたい。

最終的に、

[1, 2], [3, 5], [6, 8], [9, 10]

と出力したい。

つまり、ある要素の最大が、別の要素の最小値と同じかそれより大きい場合は、 その2つの要素を一つの要素にまとめたいということがある。

そのクエリ

WITH sample_data as (
  SELECT
    s.a AS a,
    s.z as z
  FROM (
    SELECT
      [
      STRUCT(1 as a, 2 AS z),
      STRUCT(3 as a, 4 AS z),
      STRUCT(4 as a, 5 AS z),
      STRUCT(6 as a, 7 AS z),
      STRUCT(6 as a, 8 AS z),
      STRUCT(9 as a, 10 AS z)
      ] _a)
  JOIN
  UNNEST(_a) s),
  w as (
  SELECT
    a,
    z,
    LAG(z) OVER (ORDER BY a, z) AS pre_z,
    LAG(a) OVER (ORDER BY z desc, a desc) AS post_a
  FROM sample_data
  ORDER BY a, z),
  head AS (
  SELECT DISTINCT
    a
  FROM
    w
  WHERE
    pre_z IS NULL OR
    a > pre_z),
  tail AS (
  SELECT DISTINCT
    z
  FROM
    w
  WHERE
    post_a IS NULL OR
    post_a > z),
  head_tail AS (
  SELECT
    a,
    MIN(z) AS z
  FROM
    head
  CROSS JOIN
    tail
  WHERE
    a <= z
  GROUP BY a
  ) --
--
SELECT
  *
FROM head_tail

解説

ウィンドウ関数を使って、並べた一つ上(もしくはひとつ下の)最大値(最小値)がその列の最小値より小さい(最大値より大きい)場合、まとめた要素の最小値(最大値)となる。