0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

TSVに対するSQLのSELECTもどきを作ってみた

Posted at

概要

TSVなどのちょっとした行列データを絞り込んだり、照合したりという処理を楽にするためにツールとJavaライブラリを作ってみた。

利用の前提

JDK 11 で動作確認しています。多分JRE8あたりから動くのではないかと思います。

機能

コマンドラインツール

  • 入出力ファイルのエンコード指定
  • ファイル先頭のスキップ行数指定
  • 列区切り文字の指定
  • 出力列の指定
  • ソート条件の指定
  • SQLのWHEREもどき
  • SQLのJOINもどき

Javaライブラリ

コマンドラインツールとほぼ同等ですが、SQLのWHEREもどきの表現力が上がり、Javaプログラムで使いやすくなっています。

利用例

以下は、全てダウンロードパッケージ内にサンプルとして付いていますので、色々試したい方はそちらからどうぞ。

利用するファイル

person.tsv
名前	性別	年齢	住所	趣味
佐藤	男	25	東京	旅行
鈴木	女	12	大阪	映画
山本	男	33	名古屋	工作
cities.csv
都市,人口,平均気温
東京,10000000,22.5
大阪,5000000,24.3
名古屋,3000000,23.1
福岡,1500000,25.7
仙台,1200000,19.2
札幌,1000000,15.5
hobbies.ssv
趣味;イベント;場所
旅行;浅草散策;東京
旅行;博多湾クルーズ;福岡
映画;未公開映画試聴;名古屋

シンプルなJOIN

java -jar select.jar 0@0;2@1 persons.tsv;1 cities.csv;System1Comma;INNER;3@0=0
  • 0@0;2@1
    • 0番目ファイル0列目と1番目ファイルの2列目を出力
  • persons.tsv;1
    • 0番目ファイルとしてpersions.tsvを使う
    • 先頭1行を読み飛ばす
  • cities.csv;System1Comma;INNER;3@0=0
    • 1番目ファイルとしてcities.csvを使う
    • Systemデフォルト(SJIS)エンコードで、先頭1行を読み飛ばし、列区切りはカンマとする
    • 直前のファイルとINNER JOINをする
    • 0番目ファイルの3列目とこのファイルの0列目が一致する事をJOIN条件とする
出力
佐藤	22.5
山本	23.1
鈴木	24.3

シンプルなJOIN(列名テキスト版で出力は同じ)

java -jar select.jar -c Text 名前@0;平均気温@1 persons.tsv;0 cities.csv;S0C;INNER;住所@0=都市

シンプルなWHERE

java -jar select.jar -c Text @-0 "persons.tsv;0;性別@=@男;年齢@>=@30"
  • @-0
    • -は反転マークなので、「0番目ファイルの指定列なし」の反転→0番目ファイルの全列
  • persons.tsv;0;性別@=@男;年齢@>=@30
    • 0番目ファイルとしてpersons.tsvを使う
    • 先頭0行を読み飛ばす
    • 性別が男の行だけに絞り込む
    • 年齢が30以上の行だけに絞り込む
    • ""で囲わないと、不等号がリダイレクトマークと誤認識されて意図した結果にならない
出力
山本	男	33	名古屋	工作

「男」とか「30」とかの絞り込み条件は、だいたい直感と合う様に、テキスト・整数・小数で切り替えてくれます

  • 数字だけなら64bit整数(いわゆるlong)とみなす
  • それ以外で小数と解釈できれば2倍長浮動小数(いわゆるdouble)とみなす
  • それ以外はテキストとみなす
  • ファイルの列中で指定の型(整数・小数)に解釈できない行は、絞り込み条件に合致していないとみなす

複雑な例

java -jar select.jar -c Text @-0;都市@-1;イベント@2 persons.tsv;0;性別@=@男 "cities.csv;S0C;平均気温@<@23.0;LEFT;住所@0=都市" hobbies.ssv;0SC;FULL;都市@1=場所;趣味@0=趣味
出力
佐藤	男	25	東京	旅行	10000000	22.5	浅草散策
山本	男	33	名古屋	工作	_NUL_	_NUL_	_NUL_
_NUL_	_NUL_	_NUL_	_NUL_	_NUL_	_NUL_	_NUL_	博多湾クルーズ
_NUL_	_NUL_	_NUL_	_NUL_	_NUL_	_NUL_	_NUL_	未公開映画試聴
Javaライブラリとして使って、同等の処理を行うサンプル
try (BufferedReader personReader = Files.newBufferedReader(Path.of("persons.tsv")) ;
        BufferedReader cityReader = Files.newBufferedReader(Path.of("cities.csv"), Charset.defaultCharset()) ;
        BufferedReader hobbyReader = Files.newBufferedReader(Path.of("hobbies.ssv"))) {
    Select.byText().selectAllExcept(0, null).
            selectAllExcept(1, "都市").
            select(2, "イベント").
            from(personReader).where("性別", v -> v.equals("男")).
            leftJoin(cityReader).tokenizer(Select.COMMA_TOKENIZER).
                    whereD("平均気温", v -> v < 23).on(0, "住所", "都市").
            fullJoin(hobbyReader).tokenizer(Select.SEMICOLON_TOKENIZER).
                    on(1, "都市", "場所").on(0, "趣味", "趣味").
            execute().
            map(t -> Arrays.stream(t).collect(Collectors.joining("\t"))).
            forEach(System.out::println);
}

他ツールとの比較

SQLite3などのSQLを使う方が高機能だが

  • 簡単・定型的な処理なら、簡単で高速

Linuxのjoinコマンドの方がJava不要で手軽だが

  • 事前のソート処理が不要
  • 簡易WHERE句による絞り込みが可能
  • 複数ファイルの一括JOINが可能

などの違いがある。

ご意見をいただけると助かる点

  • 似たようなツールがあれば
    • 車輪の再発明を避けるため
  • コマンドラインツールの書式の改善案
    • 絞り込みで不等号を使うと、””で囲う必要があり、ちょっとイケてない感
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?