バッチ処理のbatchって何

batch

バッチ処理とは、複数の処理をまとめて一括で処理する方法のことだ。複数の処理をバラバラで実行するよりも、まとめて実行した方が効率的ということがよくあるので、そういう時に使われる。

ところでバッチというのは聞き慣れない言葉だ。バッチの英語での綴りは batch である。バッジ badge ではない。

Batch processing が日本語でいうところのバッチ処理だ。

Computerized batch processing is the running of "jobs that can run without end user interaction, or can be scheduled to run as resources permit."

(https://en.wikipedia.org/wiki/Batch_processing)

動詞 batch や動名詞 batching で、バッチ処理をするという意味にもなってそうだ。

Batching is not an advanced feature, it's DataLoader's primary feature. Create loaders by providing a batch loading function.

(https://github.com/graphql/dataloader#batching)

調べる

SKELLという英語コーパスサイトで調べてみた。

https://skell.sketchengine.eu/#result?f=wordsketch&lang=en&query=batch

noun modified by batch を見ると、"the batch queue" や "batch processing", "batch file" など、バッチ処理のことを指していそうな言葉が並ぶ。

一方で、verbs with batch as object を見ると、"brew", "bake", "mix" など、バッチ処理と関係のなさそうな単語が並ぶ。web検索や辞書で調べると a batch of A で、パンやクッキーなどを焼くときの1回分であることが判明した。

a batch of cookies
a batch of cookies

たくさんのクッキーをまとめてオーブンに入れているイメージで、バッチ処理でデータをまとめて処理しているのかな?

そう思うと今後はバッチ処理を待っている時間も、大量のクッキーをまとめて焼いていると思えば、心穏やかに待っていられるかもしれない。そんなことはないか。

ScrapboxのページをObsidianに取り込む

文脈

最近はプライベートなノートアプリとしてObsidianを使っている。気に入ってきたので、以前使っていたScrapboxのページをインポートしたくなった。ObsidianはMarkdownがベースで、内部リンクの固有の記法があるなどの違いがある。ScrapboxMarkdownでエクスポートする機能がないので、Scrapboxで書き出したjson形式のデータをmarkdownに変換したい。

obsidian.md

scrapbox.io

やったこと

ページごとにMarkdown風テキストファイルにするスクリプトを書いた。Scrapboxの記法を正規表現で置換することを試みた。一部ではうまく置換でき、一部では置換できていない。時間はないし、インポートしないよりはマシなので、そのスクリプトで変換してObsidianにインポートした。ObsidianのインポートはただMarkdownのファイルを置くだけ。

やってみた感想

正規表現をがんばるより、パーサーを書いてみたい。その方が面白そう。

Obsidianはインラインのlatexに対応していないなど、変換できないところもあった。

Scrapboxjsonでエクスポートできる。しかしエクスポート可能であっても、記法を変換するため他アプリへでインポートするには障壁がある。

use strict;
use warnings;
use utf8;

use File::Slurp;

use JSON::XS qw(decode_json encode_json);

sub main {
    print "start\n";
    # open json file
    my $text = read_file( 'data/scrapbox.json' );
    my $data = decode_json($text);
    
    # print data info
    print($data->{name} . "\n");
    print($data->{displayName} . "\n");
    print($data->{exported} . "\n");

    my $pages = $data->{pages};

    foreach my $page (@$pages) {
        convert_page($page)
    }

}

sub convert_page {
    my ($page) = @_;
    
    my $file_name = "output/" . $page->{title} . ".md";

    my $str = "";
    my $lines = $page->{lines};
    foreach my $line (@$lines) {
        $str = $str . convert_line($line) . "\n";
    }

    open(my $fh, "> :encoding(UTF-8)", $file_name);
    $fh->print($str);

    print "saved " . $file_name . "\n";
}

sub convert_line {
    my ($line) = @_;
    
    # bold
    $line =~ s/([\w|\s]+)\[\*\* (\w+)\]/$1**$2**/g;
    # header 2
    $line =~ s/^\[\*\* (.+)\]/## $1/;
    # header 3
    $line =~ s/^\[\* (.+)\]/### $1/;
    # internal link
    $line =~ s/(.?)\[([\w|\s\.|]+)\](.?)/$1\[\[$2\]\]$3/g;
    # latex
    $line =~ s/^(.?)\[\$(.+)\](.?)/$1\$\$$2\$\$$3/;

    return $line;
}

main();
use strict;
use warnings;
use utf8;
use Test2::V0;


# bold
sub test_1 {
    my $s = "foobar [** hoge]";
    my $expected = "foobar **hoge**";
    $s =~ s/([\w|\s]+)\[\*\* (\w+)\]/$1**$2**/g;
    my $got = $s;
    is $got, $expected, "bold :  in the middle of a line";
}

test_1;


# header 2
sub test_2 {
    my $s = "[** foo bar]";
    my $expected = "## foo bar";
    $s =~ s/^\[\*\* (.+)\]/## $1/;
    my $got = $s;
    is $got, $expected, "header 2 : with space";
}

test_2;

# header 3
sub test_header_3 {
    my $s = "[* foo bar]";
    my $expected = "### foo bar";
    $s =~ s/^\[\* (.+)\]/### $1/;
    my $got = $s;
    is $got, $expected, "header 1 : with space";
}

test_header_3;


# internal link
sub test_internal_link {
    my $s = "hoge [foo bar.hoge]fuga[foobar]";
    my $expected = "hoge [[foo bar.hoge]]fuga[[foobar]]";
    $s =~ s/(.?)\[([\w|\s\.|]+)\](.?)/$1\[\[$2\]\]$3/g;
    my $got = $s;
    is $got, $expected, "internal link: in the middle of a line";
}

test_internal_link;

# latex(except inline latex)
sub test_latex {
    my $s = "[\$ \Gamma \vdash \mathit{unit}: \mathit{Unit} \phantom{-} \textbf{(Unit)}]";
    my $expected = "\$\$ \Gamma \vdash \mathit{unit}: \mathit{Unit} \phantom{-} \textbf{(Unit)}\$\$";
    $s =~ s/^(.?)\[\$(.+)\](.?)/$1\$\$$2\$\$$3/;
    my $got = $s;
    is $got, $expected, "latex(except inline latex)";
}

test_latex;

done_testing;

正規表現いろいろある

正規表現はいろいろある。

基本正規表現(BRE)がある。それとちょっと違った、+などが使える拡張正規表現(ERE)がある。

さらにPerl正規表現がある。[0-9] と同じ意味で \d とかけたりする。Perl互換正規表現としてPerl以外の言語でも使われている。

同じことをするのに複数の表現の仕方があるから混乱する。あと正規表現以外のパターンマッチもあるので混乱する。

正規表現 - Wikipedia

Perl 6 として開発が始まったRakuでは、さらに正規表現の機能を拡張して Raku rules と呼ばれるものを作ったらしい。少し気になる。

Raku rules - Wikipedia

お湯を沸かすのに必要な熱量が知りたかったから

ガスでお湯を沸かすのに何ジュールの熱量が必要なのか気になって、ポチポチ計算してたんだけど、せっかくだからコードにしとくかと思って書いてみた。最近Python触る機会も増えたから練習も兼ねてる。

"""
水の温度変化に必要な熱量の単位変換を行うクラス
"""
class WaterCalory:
    """
    水の熱量
    """ 
    def __init__(self, ml : int, delta_temp : int):
        # 水の量 ミリリットル
        self.ml = ml
        # 温度の上昇
        self.delta_temp = delta_temp

    @classmethod
    def factory(cls, ml : int, from_temp : int, to_temp : int):
        return cls(ml, to_temp - from_temp)

    def cal(self) -> int:
        # カロリー
        return self.ml * self.delta_temp

    
    def to_joule(self) -> int:
        # ジュール
        return self.cal() * 4.184

    
    def to_mega_joule(self) -> int:
        # メガジュール
        return self.to_joule() / 1_000_000


    def format_in_mega_joule(self) -> str:
        # メガジュールで少数3桁までの文字列にする
        return f"{self.to_mega_joule():.3f} MJ"
import unittest

from water_calory import WaterCalory

class TestUnionFind(unittest.TestCase):

    def test(self):
        wc = WaterCalory(1000, 60)

        self.assertEqual(
            wc.cal(),
            60_000,
            "1000mlの水を60度上昇させるのに必要な熱量は60,000カロリー"
        )

        self.assertEqual(
            wc.to_joule(),
            251_040,
            "1000mlの水を60度上昇させるのに必要な熱量は251040ジュール"
        )

        self.assertEqual(
            wc.to_mega_joule(),
            0.251040,
            "1000mlの水を60度上昇させるのに必要な熱量は0.251040メガジュール"
        )

        self.assertEqual(
            wc.format_in_mega_joule(),
            "0.251 MJ",
            "1000mlの水を60度上昇させるのに必要な熱量は0.251メガジュール"
        )

    def test2(self):
        wc = WaterCalory.factory(ml=1000, from_temp=10, to_temp=70)

        self.assertEqual(
            wc.cal(),
            60_000,
            "1000mlの水を60度上昇させるのに必要な熱量は60,000カロリー"
        )

        self.assertEqual(
            wc.to_joule(),
            251_040,
            "1000mlの水を60度上昇させるのに必要な熱量は251040ジュール"
        )

        self.assertEqual(
            wc.to_mega_joule(),
            0.251040,
            "1000mlの水を60度上昇させるのに必要な熱量は0.251040メガジュール"
        )

        self.assertEqual(
            wc.format_in_mega_joule(),
            "0.251 MJ",
            "1000mlの水を60度上昇させるのに必要な熱量は0.251メガジュール"
        )

何ジュールか変換できるようにしたから、ついでに都市ガスのジュール/立方メートル調べてガスの使用量に変換できるようにして、ガス料金の限界費用調べれば、お湯を沸かすのに必要な費用がわかる。

湯たんぽ 通販 | 無印良品

今年買ってよかったものは16cmステンレスアルミ多層鍋

ご飯が2合まで炊ける。炊飯器捨てたので、これ買ってよかった。炊飯器は置く場所をとるし、別に鍋やフライパンで炊けるので、一人暮らしでは優先順位が低い。スープも作れる。

鍋は以下の記事を参考にして宮崎製作所 ジオ 片手鍋 16cmを購入した。

料理を始める人が買うべき3つの鍋|有賀 薫|note

ヘアライン加工で艶消しされている方が好みだったが、機能性と値段のバランスが良さそうということでジオを選んだ。

鍋で炊飯するのは慣れると難しくなくて、30分水につけて、5分中火で沸騰し始めるぐらいまで加熱して、蓋をして弱火で10分加熱して、できたら火を止めて10分蒸らす。

macで使ってるalias

Twitteralias ls="ls -GF" したらいいって見かけた。自分のaliasみたけどつけてなかった。

$ alias
alias cl='clear'
alias d-c='docker-compose'
alias ll='gls -lh --time-style=long-iso --color'
alias python='python3'
alias tf='terraform'

Gは色がついて逆に見にくくなったので、ls -F だけ追加しておいた。

ll 日付見やすくしてたけど、忘れて ls -l使ってる気がする。