この記事を書いていて、JQコマンドが極めて高機能である事に改めて認識させられました。
もちろんawkもかなり汎用性の高いスクリプト言語でかつ、OSのIOに直結できるスピードを併せ持っているので、
この2つをうまくバランスよく組み合わせる事で、テキストデータベースがいとも簡単に実現できる事がわかりました。
説明が前後しますが、jqコマンドがデフォルトでインストールされていない環境の人は、apt-getやyumを使って簡単にインストールできるので、事前に入れておいてくださいね。
便利に使えるようになると、他サイトのAPIなどから取得したjsonを非常に簡単に整形したり、そのサイト専用の形式にコンバートしたりする事が可能になるので、超オススメです。
ソースコードと実行
<?php
namespace textDatabase;
/**
* 保存したデータを読み込む
*/
class dataReadShell{
// count
public static function get_count_csv($filename){
unset($res);
exec("wc -l ".$filename.".csv | cut -d' ' -f1" , $res);
return $res[0];
}
public static function get_count_json($filename){
unset($res);
exec("cat ".$filename.".json | jq -c '. | length ' " , $res);
return $res[0];
}
public static function get_count_json_multi($filename){
unset($res);
$cmd = array(
"cat ". $filename .".multi.json",
"tr '\\n' ',' | sed -e 's/,$//' ",
"echo '[' $(cat) ']'",
" jq -c '. | length ' "
);
exec(join(" | " , $cmd) , $res);
return $res[0];
}
// price-sum
public static function get_sum_csv($filename){
unset($res);
$cmd = array(
" cat ". $filename .".csv ",
" cut -d, -f3 ",
" tr -d ',' ",
" awk 'BEGIN{num=0}{num += $1}END{print num}' "
);
exec(join(" | " , $cmd) , $res);
return $res[0];
}
public static function get_sum_json($filename){
unset($res);
$cmd = array(
"cat ". $filename .".json",
" jq -r '[.[] | .price |tostring | sub(\",\"; \"\") | tonumber] | add' "
);
exec(join(" | " , $cmd) , $res);
return join("-",$res);
return $res[0];
}
public static function get_sum_json_multi($filename){
unset($res);
$cmd = array(
" cat ". $filename .".multi.json ",
" tr '\\n' ',' | sed -e 's/,$//' ",
" echo '[' $(cat) ']' ",
" jq -rc '.[] | .price' ",
" tr -d ',' ",
" tr '\\n' ',' ",
" sed -e 's/,$//' ",
" echo '[' $(cat) ']' ",
" jq -r '. | add' "
);
exec(join(" | " , $cmd) , $res);
// echo "--".join(" | " , $cmd).PHP_EOL;
return $res[0];
}
}
// 登録件数
$res_csv_1 = \textDatabase\dataReadShell::get_count_csv("data");
$res_json_1 = \textDatabase\dataReadShell::get_count_json("data");
$res_json_multi_1 = \textDatabase\dataReadShell::get_count_json_multi("data");
echo "[count]".PHP_EOL;
echo "csv : ". $res_csv_1 .PHP_EOL;
echo "json : ". $res_json_1 . PHP_EOL;
echo "json-multi : ". $res_json_multi_1 . PHP_EOL;
// price値の合計値
$res_csv_2 = \textDatabase\dataReadShell::get_sum_csv("data");
$res_json_2 = \textDatabase\dataReadShell::get_sum_json("data");
$res_json_multi_2 = \textDatabase\dataReadShell::get_sum_json_multi("data");
echo "[price-sum]".PHP_EOL;
echo "csv : ". $res_csv_2 .PHP_EOL;
echo "json : ". $res_json_2 . PHP_EOL;
echo "json-multi : ". $res_json_multi_2 .PHP_EOL;
exit("finish !");
ソース解説
今回もcsv形式とjson形式、改行区切りのjson(multi)形式の3パターンの読み込みサンプルをコーディングしてみましたが、それぞ
れ「登録されているデータ数」「priceの値の合計値」をexec部分のみで計算してみました。
ようするにPHPはコマンドを実行して、それを受け取って表示しているだけなので、これをPHP処理とは言わないレベルですが、このやり方を覚えた方がデータの扱いがはるかに楽になるので、この段階で、こうしたやり方が苦手な人は習得してみましょう。
登録数の読み取り
csv形式は、単純に改行数だけ数えればいいので、"wc -l 読み込みファイル名"で実現しています。
awkを使ってもいいですが、シンプルイズベストの精神でいろいろなコマンドを駆使すると他にも色々な発見や、発展に繋がります。
json形式は、root階層が配列構造になっているので、その配列の要素数をjqのlengthコマンドで簡単に取得できます。
json-multi形式では、改行毎にjson形式になっていて、全体を一度大きな配列に変換して、その要素数を取得しています。
少しふぐ雑ですが、csvのように改行数で取得してもいいかもしれませんが、こうした理由としては、データの内部にSQLのようなid値を埋め込んで追記していく時に、重複したid値は計測したくない場合など、この方式でユニーク値排除する事が可能になります。
priceの合計値
csvでは、price部分の3番目のカラムをcutコマンドで抽出して、","を今回は数値として扱いたいので、排除する処理を加えて、awkに渡します。
awkでは、受け取った数値を全て足し混んで最終地を表示しているだけですが、ここの四則演算を変えるだけで、差額値の取得や、色々な計算結果を得られる事がわかります。
json形式は、catでdata.jsonデータをそのまま受け取りjqコマンドのみで、合計値の計算を行なっています。
少しイレギュラーだったのが、金額が文字列のモノと、数値のモノがあったので、一旦全て数値変換するところが煩雑になっていますが、文字列置換など、他でも使える要素なのであえてサンプルコードとして掲載してみました。
最初にtostringとして、数値と文字列が入り混じっているのを全て文字列に変換してから、カンマ(,)文字列をsubコマンドでreplaceします。
その後tonumberで数値に戻す事で、数値の一覧を配列で保持して、それをaddコマンドで合計値が得られます。
最後にjson-multi形式は、上記のjsonと同じやり方でもいいのですが、jqに渡す前に、文字列をtrでreplaceして、最後のjqで合計値計算だけを行なっているので、処理をそれぞれパイプに振り分けた状態で書いてみました。
とんでもないことに気が付いた
このデータは、priceは単価で、その横にcountという個数を入れていたのを思い出しました。
合計値の計算は、単価の計算ではなく、商品別に「単価×個数」の全ての合計にしなければいけませんでしたね。
とりあえず、今回は、計算の序盤ということで次回に個数計算を加えてみたいと思います。
0 件のコメント:
コメントを投稿