はじまる

適当な事を適当に書く

ロジカル!男のハンバーグ、ミニマムレシピ

ハンバーグ

基本的にひき肉を焼いて食べるものを指すと思う。しかし、例えば、ひき肉をスーパーから買ってきたパックからそのままだして、フライパンで焼くと下記のようになるはず。

  • そぼろのようにバラバラになって、かたちがまとまらない
  • 味がしない

 

巷のハンバーグのレシピというものは、実はこの2つの事象を防ぐように構成されている、というのがいくつかのハンバーグレシピを試してみて持った持論だ。これはの課題さえ克服していれば、実はハンバーグは、味付けやその他の構成要素などもすべて調理者に委ねられる、非常に自由度の高い料理といって良いのではないか、と最近は思っている。これらの課題を克服した最低限のハンバーグは以下のようなものになる。

 

ハンバーグのミニマムレシピ

材料
  • ひき肉
  • パン粉
工程

これらをこねて円盤状にして、フライパンで両面を焼く。中心まで赤い部分がなくなり、完全に火が通ったら食べられる(食中毒の心配がない)。雑で。工程より以下の理由のほうがだいじ。

 

なぜパン粉を加えるか?

ひき肉は加熱とともに、肉汁(血、油)がフライパンに流れ落ちる。生肉を安全に食せるまで十分に加熱した結果、できあがったハンバーグはたいてい下記のようになる。

  • 味がしない
  • 割れやすい

 

この2つの課題を解決するのがパン粉だ。パン粉が、加熱により流れ出ようとする肉汁をハンバーグ内に吸着することで、味を留める役割を担う。また、肉汁を吸収したパン粉は粘度をまして、バラバラに肉塊を固めるのだ。

 

加熱時間を押さえれば、肉汁の流出も中まで火が通らない状態になる。病原菌の少ない牛肉100%のひき肉であればそれでも良いが、豚肉を含む場合、病原菌が死滅するまで十分に加熱する必要がある。中途半端な加熱は豚肉にはありえないのだ。その結果肉汁はすべて流れ出すことになる。豚肉を含むハンバーグでは、パン粉は不可欠だ、というのがハンバーグを作るなかで確信したことである。

ただし、パン粉を加えすぎると、お好み焼きのような風味になるので注意。

 

なぜ塩を加えるか

水分を減らすことにより肉塊がバラバラに分解するのをふせぐ、と言われている。ただし吸着効果としてはパン粉のほうが強力なので、効率的な味付けの意味合いも強いようだ。焼けたあとに外側から味付けするのもいいが、ひき肉にたいして万遍なく下味がついているほうがいい場合が多いだろう。

Treasure Data Workflow (digdag) でテーブルを任意の行数単位で分割して、動的にループする

背景(例)

  • 1億レコードのテーブルがある。
  • テーブルに対してクエリを実行したい。
  • 実行してみたら重たかったので並列処理したい。
  • 100万レコードごとにテーブルを分割して、各テーブルごとにクエリを実行する。

Treasure Data のテーブルインデックスについて

Treasure Data のテーブルは、time というlong 型の列を必ず持つ仕様となっている。このtimeが、標準ではTreasure Data のテーブルの唯一のインデックスにもなっている。time には unix timestamp が数値で入る想定で、Treasure Data が時系列データのビッグデータ分析基盤から始まったことの名残である、と思われる。

このtime,実はlong値であれば、unixtime スタンプでない値もいれることができる。テーブルを任意のレコード件数で分割したいとき、このtime列に分割の基準となる値をいれることで、分割処理でインデックスが効くようになり、処理時間を早めることができる。

こんな感じ

#main.dig

###############################################################
# 環境変数設定
###############################################################

_export:
  td:
    database: hoge
    table: fuga
    split_size: 1000000
  

###############################################################
# 処理
###############################################################


+create_indexed_view:
# time を row_num 列として利用し、テーブルのレコードを分割する。
# https://qiita.com/mumuma/items/faa76b50ca653d85d522
  td>: create_indexed_view.sql
  create_table: ${td.database}.${td.table}_view_${session_date.replaceAll('-', '_')}
  engine: hive

+count_records:
  td>:
  query: "select count(time) as count from ${td.database}.${td.table}"
  store_last_results: true

+caluculate_loop:
# ここで、レコード件数と、分割サイズをもとに、必要なloopの回数を計算する。
  td>: 
  query: "select cast(ceiling( ${td.last_results.count} / (${td.split_size} * 1.0)) AS INTEGER) as loop;"
  store_last_results: true

+p4:
  loop>: ${td.last_results.loop} 
  _parallel:
    limit: 3
  _do:
    +table_split:
      td>: 1.sql
-- create_indexed_view.sql
SELECT 
  row_number() over(order by order_no)as time
  ,column1
  ,column2
FROM
  ${td.database}.${td.table}
-- split.sql
SELECT * FROM ${td.database}.${td.table}
WHERE time BETWEEN (1+${i}*${td.split_size}) AND (${i}+1)*${td.split_size}

Mac OS ventura にアップデートしたら git が行方不明になった。

git 実行時にエラーがでるようになってしまった。

% which git
/usr/bin/git
% git
xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun

Gitコマンドでxcrun: errorが出た時の対処 - Qiita をみて、Xcode を再インストールしたら直りました。

% git
usage: git [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]
           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]
           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
           [--super-prefix=<path>] [--config-env=<name>=<envvar>]
           <command> [<args>]

These are common Git commands used in various situations:

start a working area (see also: git help tutorial)
   clone     Clone a repository into a new directory
   init      Create an empty Git repository or reinitialize an existing one
...

先人の皆様ありがとう…。

都内作業に適したカフェ・公共施設

そこまで混んでないとこ。

 

カフェオアシス 秋葉原

https://tabelog.com/tokyo/A1311/A131101/13269704/

東京メトロ 末広町駅

 

カフェベローチェ 八重洲

東京メトロ 日本橋

JR 東京駅

 

ドトールコーヒー 神田店

東京メトロ 神田駅

 

CABABRE

https://tabelog.com/tokyo/A1311/A131101/13280539/

東京メトロ 上野広小路駅

JR御徒町駅上野駅

リニューアルしたらしいからいまは作業に適してるか不明

 

Aesop Rock x Blockhead - Pumpkin Seeds (feat. Lupe Fiasco) の歌詞

www.youtube.com

歌詞は動画の概要欄に載っている。

Outside isn’t what it seem It seem like nothing up the sleeve Until it’s something loveless digging holes to cover up with leaves

外は見た目とは違う それは何もないように見える 愛のないものになるまで 穴を掘って葉っぱで覆い隠す

Between you and your pumpkin seeds, and powerball, and Sunkist Peach at 1 or 1:15 AM When all you want is drugs and peace All you get is waves and waves of uninvited company Ranger, cleric, hunter, thief Druid, Vandal, huckster, Priest

あなたとカボチャの種パワーボールサンキストのピーチジュースの間 午前 1 時または 1 時 15 分頃 あなたがドラッグと平和だけを望む頃 波と招かれざる仲間達がやってくる レンジャー、クレリック、ハンター、シーフ ドルイド、ヴァンダル、ハックスター、プリースト

Amateur usurpers and catechism deserters, re-tuning truffle pig noses to catalytic converters

マチュアの簒奪者とカテキズムの脱走兵、トリュフ豚の鼻を触媒コンバーターに再調整

In between the stirring creatures, I’m keen to the furthest needle drop Before requesting stitches, it is not that type of needle dog

興奮を誘うクリーチャーたちの中にいても 私の感覚は遠くで落ちる針の音も聞き逃さないほど冴えている 裁縫を依頼する前に聞いて、私はフェルトでつくられた犬ではない

Dog, the truest unicorn of all is human at rest Waltzing through some hood the future forgets

犬よ、一角獣とは死後の人々 未来に忘れられた人々の合間を縫ってワルツを踊る

I just been cooped up in that cuckoo's nest, one phase after complaining, which depending on your frame is apathy or acclimating Happy cutting off and jumping in and yelling someone shut the top It isn’t just some funyun run that got him on that “cut the lock”, it’s

私はカッコウの巣(※精神病棟の軽蔑的な語)に閉じ込められ 不平を言った後の一言は あなたを模るものが共感か無関心か、それ次第 ハッピーカットオフ、そしてジャンプイン 叫んで誰かが頂上に向かって叫ぶ オニオンリングのスナック菓子も走り込んできて叫ぶ「錠前をねじ切ってしまえ」

Inside of the box is just another box Inside of the box is just another box

箱の中にはまた別の箱 箱の中にはまた別の箱

You should probably get accustomed to the culture shock Plot to jump behind some bushes when they cull the flock

カルチャーショックには慣れた方がいい 群れが間引かれている 茂みの後ろに隠れよう(※おそらく人間の群れを指している)

Inside of the box is just another box Inside of the box is just another box

箱の中にはまた別の箱 箱の中にはまた別の箱

You should probably get some wind up in your mutton chops Note the general tone is get the dough, and fuck the ops

外の風に吹かれよう 頰髯の面を 小麦粉の生地のような単調な日々

Postgres JSON (JSON配列)データの要素にアクセスするための演算子一覧

はじめに

こんなJSONの配列データがあったとします。

[{"a":"foo"},{"b":"bar"},{"c":"baz"}]

PostgreSQL だとこう。

SELECT '[{"a":"foo"},{"b":"bar"},{"c":"baz"}]'::json as example
example
[{"a":"foo"},{"b":"bar"},{"c":"baz"}]

こんなJSONのデータをPostgreSQL で扱う際の演算子と関数一覧です。json型のみでjsonb型は省いています。 元ネタは PostgreSQL 14.0文書です。

演算子

要素にアクセスするための演算子 ->

配列の添字を指定して要素にアクセスする。

SELECT '[{"a":"foo"},{"b":"bar"},{"c":"baz"}]'::json -> 2 as second_element
second_element
{"c":"baz"}

配列の添字(逆順)を指定して配列の要素(オブジェクト)にアクセスする。

SELECT '[{"a":"foo"},{"b":"bar"},{"c":"baz"}]'::json -> -1 as last_element
last_element
{"c":"baz"}

配列の添字(逆順)を指定して配列の要素(オブジェクト)にアクセスし、さらにオブジェクトのキーを指定して値を取得する。 添字の指定にも、オブジェクトのキーの指定にも -> を利用する。

SELECT
    last_element -> 'c' as value -- {"c":"baz"} の key を指定してvalueを得る
FROM
    (
        SELECT
            '[{"a":"foo"},{"b":"bar"},{"c":"baz"}]' :: json -> -1 as last_element
    ) as _
value
"baz"

要素にアクセスしてテキスト型で値を取得するための演算子 ->>

わかりづらいが、ここでの戻り値はテキスト型になっている。

SELECT '[{"a":"foo"},{"b":"bar"},{"c":"baz"}]'::json ->> 0 as str
str
{"a":"foo"}

戻り値はテキスト型のため、JSON型データへの演算子を利用するとエラーになる。

SELECT
    str -> 'a' -- ここで str は '{"a":"foo"}'になっている。
FROM
    (
        SELECT
            '[{"a":"foo"},{"b":"bar"},{"c":"baz"}]' :: json ->> 0 as str
    ) as _
ERROR:  operator does not exist: text -> unknown
LINE 1: SELECT str -> 'a' FROM (
                   ^
HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.

-> と同様にオブジェクトのキーを指定して値にアクセスする場合にも利用できる。

SELECT '{"a":1,"b":2}'::json ->> 'b' as str
str
2

JSONのパスを指定して要素にアクセスするための演算子 #>

{}のなかに、 -> の引数になるような値を書き連ねていくことで、JSON木構造を辿って要素にアクセスできる。

SELECT '[{"a":"foo"},{"b":"bar"},{"c":"baz"}]'::json #> '{0}' as example
example
{"a":"foo"}
SELECT '[{"a":"foo"},{"b":"bar"},{"c":"baz"}]'::json #> '{0,a}' as example
example
"foo"

JSONのパスを指定して要素にアクセスしてテキスト型で値を取得するための演算子 #>>

上記の別バージョンで、戻り値の型がテキスト型になる。

SELECT '[{"a":"foo"},{"b":"bar"},{"c":"baz"}]'::json #>> '{0}' as str
str
{"a":"foo"}
SELECT '[{"a":"foo"},{"b":"bar"},{"c":"baz"}]'::json #>> '{0,a}' as str
str
foo

文字列として保存した PostgreSQL の JSON を Python でも JSON として扱う

はじめに

コーナーケースすぎるけど下記のようなケースです。

  • Python プログラムから直接PostgreSQLに接続するのでなく、Postgres のJSON配列の値を、ほかのデータベースのテキスト型の列か、ファイルなどに、文字列、テキストとして保存する
  • Pythonからはその保存されたデータを読み込んで、PythonJSONとして扱いたい

PostgreSQL

Postgres あるテーブルからデータをJSON 型で抽出するときの小ネタ - はじまる で使った Animals テーブルをまた利用します。

SELECT * FROM Animals;
 id    name   age   kind  
 1    Mickey   5   Mouse
 2    Snoopy   3   Dog
 3    Kitty   3   Cat

これを array_agg などでJSONを格納した配列に変換します。

WITH 
AnimalJSON AS (
    SELECT
        id,
        (
            select
                row_to_json(_)
            from
                (select name, age, kind) as _
        ) as attributes
    FROM
        Animals
)
SELECT
    array_agg(attributes)
FROM
    AnimalJSON
array_agg
{"{\"name\":\"Mickey\",\"age\":5,\"kind\":\"Mouse\"}","{\"name\":\"Snoopy\",\"age\":3,\"kind\":\"Dog\"}","{\"name\":\"Kitty\",\"age\":3,\"kind\":\"Cat\"}"}

この値が適当なデータストアに保存されており、それをPythonで扱いたい時の話です。

Python

上記の array_agg の結果が、文字列として格納されている状態です。Python から読み取り、 str 型の変数 string に入力されているとします。

print(string)
>>>{"{\"name\":\"Mickey\",\"age\":5,\"kind\":\"Mouse\"}","{\"name\":\"Snoopy\",\"age\":3,\"kind\":\"Dog\"}","{\"name\":\"Kitty\",\"age\":3,\"kind\":\"Cat\"}"}

print(repr(string))
>>>'{"{\\"name\\":\\"Mickey\\",\\"age\\":5,\\"kind\\":\\"Mouse\\"}","{\\"name\\":\\"Snoopy\\",\\"age\\":3,\\"kind\\":\\"Dog\\"}","{\\"name\\":\\"Kitty\\",\\"age\\":3,\\"kind\\":\\"Cat\\"}"}'

この string をどうPython での JSONに変えていくかですが、結論としては下記のようなアプローチがいいかと感じました。

  1. str から set に変換する
  2. set から JSON に変換する

まず eval() を使うことで、str から set に型変換します。

>>> string = repr(string)
>>> type(string)
<class 'str'>
>>> eval(string)
{'{"name":"Kitty","age":3,"kind":"Cat"}', '{"name":"Snoopy","age":3,"kind":"Dog"}', '{"name":"Mickey","age":5,"kind":"Mouse"}'}
>>> type(eval(string))
<class 'set'>

ここで、配列の要素はまだ文字列になっています。これらの文字列を json.loads()JSONとしてパースします。

>>> new_list = []
>>> if type(eval(string)) == set:
...   for i in eval(string):
...     item = json.loads(i)
...     new_list.append(item)
... 
>>> new_list
[{'name': 'Kitty', 'age': 3, 'kind': 'Cat'}, {'name': 'Snoopy', 'age': 3, 'kind': 'Dog'}, {'name': 'Mickey', 'age': 5, 'kind': 'Mouse'}]

これでようやくPostgresでの JSONPython でも同様のJSONとして扱えるようになりました。