山本ゆうごブログ

山本ゆうごの仕事メモ

RDBにバイナリファイルを置くメリット

RDBにはBLOB型があって、そこにはバイナリファイルを置くこともできる。

あんまり有り難みがないかもしれないだけれど、個人的には結構よく使ってる。

以下、いいところだけをピックアップする

複数マシンから寄ってたかって使いたいとき

処理マシンのローカルにファイルを置くと共有できない。NFSみたいなものを使えばいいのだけれどそういうの作るのが面倒。開発環境と本番環境で揃えるのも面倒だ。

削除がしやすい

大量のファイルをローカルストレージに置いちゃうと、rm -rf だけですごい時間がかかっちゃう。黙ったままなので進捗も分からない。これが、RDBに置いたら、trancate 一発で削除できる。そもそもローカルストレージでファイルが多いと、lsだけでもビタット止まっちゃう。

ステータス管理しやすい

RDBなので、BLOB型の隣には、status(int) みたいな適当なフィールドを作っておいて、この画像サムネイル作ったっけ?みたいなステータス管理がしやすい。キューもかねたストレージとして扱える。

集計しやすい

select DATE_FORMAT(updated_at,'%Y/%m/%d %H') as ymdh, count(updated_at) as cnt  from テーブル名  group by ymdh;

こんな感じで、一時間おきのファイルの更新ペーストとかが分かる。

メモリに載せやすい

MySQLにはクエリキャッシュの機能がある。イマドキはいっぱい詰めるので、極端なはなしDBの中身が全部乗っけることもできる。クエリキャッシュは元データが変わるとキャッシュも破棄されるので、プログラマが意識する必要がない。どれくらいキャッシュにヒットしたかもSQL一発で分かる。ディスクのIOよりも、ネットワーク越しのメモリアクセスの方が管理しやすいってこともある。

SequelProならバイナリファイルもそのままみれる

SequelProというMySQLクライアントがめちゃくちゃよくできていて、バイナリファイルはプレビューができちゃう。jpgだけじゃなくてPDFまでプレビューしてくれる。めちゃくちゃ高速に検索できるファイルサーバとして使える。

そもそも、S3でいいのでは?

それはそもそう。容量あたりの単価も安い。ただ、ステータス管理とかしたくなると、S3のメタデータだけだとやや不便。そこは別途キューとかRDBでステータス管理したくなる。惜しい。「今日更新されたファイル一覧が欲しい」って検索条件がぱっと思いつかない。

僕はいつもこんな感じでざくっとデータをみている

CSVがドーンとあったとする。その際にどうやってデータを見るかってのは、なんとなくの手順がある。その手順を示しておく。

wc -l でみる

まずは行数をみる。10万行とか超えちゃうとExcelでは重すぎてみれない。

less コマンドでみる

そして中を確認する。lessコマンドでみれるのはutf8縛りなので、SJISの場合は別のエディタなどで開く。 中身が何かを確認する。 先頭にBOMがついているかどうかや、LF改行なのか、CRLF改行なのかくらいはここで分かる。 大きなファイルも早く開けるのがlessコマンド。先頭行と最終行はチェックする。

Excelでみる

文字コードを変換する

nkf -s utf8.csv > sjis.sv

で、SJISに変換する。UNICODEのままでExcelで開きたかったら、以下のコマンドでBOMをつける。

cat <(printf "\xEF\xBB\xBF") 元ファイル > BOMつきファイル

Excelで開く

数値の前ゼロが取れちゃうから、普通はCSVをダブルクリックしちゃだめなんだけど、参照専用と割り切って、ダブルクリックして開いちゃう。

フィルタをかける

フィルタをかけて、▼をクリックする、そうするとどういうデータがあるかが分かる。空白の存在などもここで分かる。ゴミデータが入ってないかが分かる。

ピボットテーブルを作る

ピボットテーブルを作ることで、データの分布が分かる。特に日付のフィールドがあれば、ピボットテーブルを日付でグループ化して、年単位や月単位の分布をみて、傾向をつかむ。

mysqlの場合

CSV単体が見づらい場合はmysqlなどのRDBでみる。

ひたすら並びかえる

データの異常値がないかどうかは、ひたすら並びかえて確認する。sequel proやphpmyadmin などのツールであれば、sqlを書くこと無く並び替えが用意なので、そこでみる。

ひたすらグループ化する

select DATE_FORMAT(updated_at,'%Y/%m/%d %H') as ymdh, count(updated_at) as cnt  from テーブル名 
group by ymdh;

こんな感じで、時間単位の更新時間を並べて見て、どういう処理ペースで動いているかを確認したりする。

そのままメールに出力結果を貼り付けたい時などは、FORMAT関数でカンマ区切りにしたり、LPAD関数で左空白詰めをして右揃えにしたりする。

BiqQueryの場合

MySQLだけだと、数百万件を超えるデータは扱いにくい。並び替えやグループ化をするデータはインデックスを貼ればいいのだが、インデックスをはるにもマシンパワーが余分にとられる。そこまでくれば、インデックスに気を使わなくてもいい、BigQueryをつかうのがいい。

ただ、CSVを参照可能にするにもそこそこの手間がかかる。

CSVはUTF8

UTF8のダブルクォート区切り。フィールド内ダブルクォートはダブルクォート二重でエスケープ。

CSVをgz形式にする

BiqQueryに入れるレベルのCSVファイルは、GBを超えるくらいなので、アップロードに時間をかけなくてもいいように、giz圧縮をする。

gzip -c data.csv > data.csv.gz

Google Cloud Strageにアップする

gsutil cp data.csv.gz gs://bucket/data.csv.gz

この段階で、Googleの認証が必要。gsutilもインストールしてる前提。認証は、gsutil auth で認証をする。

この際に、GoogleCloudStrageのプロジェクトIDが必要。GoogleCloudStrageのプロジェクトIDとBigQueryのプロジェクトIDは同じ方が権限的に楽。

bq コマンドでロードする

bq load --source_format=CSV  --skip_leading_rows=1 --project_id=XXX aaa.gz   gs://zzzz/aaa.gz \
id:integer,\
name:string

各カラム名とその型を、スキーマとして引数にしていしている。シェルとしては一行だけど、見づらいのでバックスラッシュで改行を入れている。

bq コマンドを最初につかうときにもGoogleの認証は聞かれる。 AWSみたいなアプリケーションキーを環境変数に入れておくというような手法でない。accountを切り替えるのは面倒。

BiqQueryで集計して、レポートにする

ひたすらグループ化のSQLをたたく。集計の結果は、SpreaSheetに出力できるので、ポンポン出力する。適当なファイル名で出力されるので、出力されるたびに、スプレッドシートのファイル名を変えたほうがいい。

スプレッドシートに出せば、グラフにポンポン変換できるので、グラフ化して、スライドの資料にポンポン貼っていけばいい。スプレッドシートには、SPARKLINEという関数があって、セルの中にちょっとしたグラフをかける。Excelでいうデータバーみたいなことができるので手軽。

f:id:yugo_yamamoto:20171015103510p:plain

ポンチ絵のナゾ

ポンチ絵は大事で嫌い

ポンチ絵は嫌われている。

Bubbles don't crash! という言葉がある。Bubbles というのは、ドキュメント上に書かれた図形のことで、ドキュメントをいくら頑張って描いても、その間違いって気づき用がないということ。だからエンジニアの間では、ソースコードの方が重視される。それがシステムを表しているし、間違っていたらエラーがでる。

しかしながら、ソースコードを見せてもそれが何なのかはわからないし。プログラムの外のこと(ユーザーとか銀行とかとの関係)は分からない。

そのシステムの社会的な位置付けを示したいときには、どうしてもポンチ絵が必要になる。大事なのは「システムの外」ということ。

規格としてのポンチ絵 UML

UMLという規格はあるのだが、ポンチ絵にはあまり役に立たない。基本は「自社のシステム」を作るためのものであって、他者との座組を示すものではないから。

ポンチ絵の定義

ラフイメージという位置付け。ハードウェア業界の人達は、製品の完成イメージ図や設計図のラフイメージをポンチ絵と言うし、企業ごとの提携を示すにもポンチ絵という呼び方をする。

ここでは、相関図をポンチ絵を呼ぶことにする。

ビジネスマンでなくてもポンチ絵は大事

例えばオリラジ中田のブログ。 http://lineblog.me/atshikonakata/ https://obs.line-scdn.net/0hWjYbkdvnCEVkGybdC6R3Ei5GDiodeBJNDmMffxFNAmsRdx9FDGEXZgNCDi8XdB9JCDgXPzVoADECLxRDXA9AUUJSLAlKQj1bDgpHKidHCCUKdAZHRH1CK0MbVHZIKkYTUC9PI0QZE3ROKRwaUChO

めちゃくちゃポンチ絵を使ってる。

ポンチ絵のわかりづらさ

学問がない

文学でもない。経済でもない。自然科学でもない。一番近いのは語学ではあるが、ジャンルとして存在していない。だから習うことができない。

ルールがない

ルール化されたのがUMLではあるが、一般的ではない。

ハンディキャップ仮説としてのポンチ絵の存在

本当にコミュニケーションを円滑に刷るために作られたのかさえ怪しい。「頑張って図がいっぱい入ったパワポ資料を作りました」ってスタイルは存在する。

というとで色々サンプルをみながらポンチ絵の存在をみてみよう

日経新聞はこれ http://www.nikkei.com/paper/article/?b=20170502&ng=DGKKZO15973950S7A500C1MM8000 http://www.nikkei.com/paper/image-article/?R_FLG=0&ad=DSKKZO1596443001052017MM8000&ng=DGKKZO15973950S7A500C1MM8000&z=20170502

日経新聞なので、登場人物やら組織やらの間を矢印で繋いで、お金の流れを表すということが多い。

http://www.nikkei.com/paper/article/?b=20170502&ng=DGKKZO15970070R00C17A5TI1000 http://www.nikkei.com/paper/image-article/?R_FLG=0&ad=DSKKZO1597009001052017TI1000&ng=DGKKZO15970070R00C17A5TI1000&z=20170502

この図の場合はもやは矢印が何かさえ言い表してはない。ただ、登場人物は明らかで、なんらかの取引のルールとが矢印で表されているということだけは分かる。

ポンチ絵で抑えるべき箇所

  • 登場人物を箱で書く
  • データ・モノ・お金の流れを矢印で書く

登場人物(組織)を発注などの情報を矢印で結ぶ。「誰が」→「誰に」という風にイベントのトリガーを元にする。 複数の登場人物がいる場合には、直接コミュニケーションをとっているのが誰かというだけでも分かりやすい。

アマゾンの例では、発注の流れではなく、在庫の流れを示してると思われる。普段は出版社はAmazonと直接取り引きをしていないが、日販に在庫がない場合には直接取引をしていることを示している。

形にはこだわりすぎない

日経のAmazonの例をみてみる。出版社はビルだし、日販は本の束だし、AmazonAmazonと書いているだけだ。じゃぁそれが分かりにくいかっていうとそうでもない。Amazonも何らかのイラストつけてあげなよとは思うけど、そこをモタモタするくらいなら、単なる長方形でいい。

社内用途ではロゴが分かりやすい

ロゴって勝手に使っちゃいけないから社外向けのドキュメントには書きづらい。日経もそうだと思う。一方でビジネス用途では本当にその会社を示すためにロゴを使いたいときもあるので、そういうときにはロゴを使った方が視認性が高い。

osxにphp7.1をインストール

brew でインストールできる。

$ brew search php7

これで、php7.0と7.1の両方があることが分かる(2017/02/17現在)。

んで、php7.1の方が速いらしいので、それを入れる。すると、php5.6とコンフリクトしているから、php5.6をunlinkしろと言われる。素直にunlink。unlink はアンインストールではないのであまりためらわずに。

==> Installing php71 from homebrew/php
Error: Cannot install homebrew/php/php71 because conflicting formulae are installed.

  php56: because different php versions install the same binaries.

Please `brew unlink php56` before continuing.

あれためて、インストール

$ brew install php71

すると、こんなインストールログ。

The php.ini file can be found in:
    /usr/local/etc/php/7.1/php.ini

✩✩✩✩ Extensions ✩✩✩✩

If you are having issues with custom extension compiling, ensure that
you are using the brew version, by placing /usr/local/bin before /usr/sbin in your PATH:

      PATH="/usr/local/bin:$PATH"

PHP71 Extensions will always be compiled against this PHP. Please install them
using --without-homebrew-php to enable compiling against system PHP.

✩✩✩✩ PHP CLI ✩✩✩✩

If you wish to swap the PHP you use on the command line, you should add the following to ~/.bashrc,
~/.zshrc, ~/.profile or your shell's equivalent configuration file:

      export PATH="$(brew --prefix homebrew/php/php71)/bin:$PATH"

✩✩✩✩ FPM ✩✩✩✩

To launch php-fpm on startup:
    mkdir -p ~/Library/LaunchAgents
    cp /usr/local/opt/php71/homebrew.mxcl.php71.plist ~/Library/LaunchAgents/
    launchctl load -w ~/Library/LaunchAgents/homebrew.mxcl.php71.plist

The control script is located at /usr/local/opt/php71/sbin/php71-fpm

OS X 10.8 and newer come with php-fpm pre-installed, to ensure you are using the brew version you need to make sure /usr/local/sbin is before /usr/sbin in your PATH:

  PATH="/usr/local/sbin:$PATH"

You may also need to edit the plist to use the correct "UserName".

Please note that the plist was called 'homebrew-php.josegonzalez.php71.plist' in old versions
of this formula.

With the release of macOS Sierra the Apache module is now not built by default. If you want to build it on your system
you have to install php with the --with-httpd24 option. See  brew options php71  for more details.

To have launchd start homebrew/php/php71 now and restart at login:
  brew services start homebrew/php/php71
==> Summary
🍺  /usr/local/Cellar/php71/7.1.1_12: 344 files, 39.7M

php.ini の場所とか、新しくなってるので要注意。PHP-FPMもデフォルトで面倒みてくれている。いよいよ、PHPApacheの付属のものではなく、自立し始めている感。とはいえ、直近ではまだまだApacheもつかいますと。Apache向けのモジュールはどこにあるかなぁと思って、探すとない。インストールログをあらためてみると、

With the release of macOS Sierra the Apache module is now not built by default

って思いっきり書いてある。

なので、オプションを付けて再インストール。install ではなく reinsall ね。

$ brew install php71 --with-httpd24 

するとこんなインストールログ。Apacheモジュールも入ってるっぽい。

To enable PHP in Apache add the following to httpd.conf and restart Apache:
    LoadModule php7_module    /usr/local/opt/php71/libexec/apache2/libphp7.so
    
    <FilesMatch .php$>
        SetHandler application/x-httpd-php
    </FilesMatch>

Finally, check DirectoryIndex includes index.php
    DirectoryIndex index.php index.html

The php.ini file can be found in:
    /usr/local/etc/php/7.1/php.ini

✩✩✩✩ Extensions ✩✩✩✩

If you are having issues with custom extension compiling, ensure that
you are using the brew version, by placing /usr/local/bin before /usr/sbin in your PATH:

      PATH="/usr/local/bin:$PATH"

PHP71 Extensions will always be compiled against this PHP. Please install them
using --without-homebrew-php to enable compiling against system PHP.

✩✩✩✩ PHP CLI ✩✩✩✩

If you wish to swap the PHP you use on the command line, you should add the following to ~/.bashrc,
~/.zshrc, ~/.profile or your shell's equivalent configuration file:

      export PATH="$(brew --prefix homebrew/php/php71)/bin:$PATH"

✩✩✩✩ FPM ✩✩✩✩

To launch php-fpm on startup:
    mkdir -p ~/Library/LaunchAgents
    cp /usr/local/opt/php71/homebrew.mxcl.php71.plist ~/Library/LaunchAgents/
    launchctl load -w ~/Library/LaunchAgents/homebrew.mxcl.php71.plist

The control script is located at /usr/local/opt/php71/sbin/php71-fpm

OS X 10.8 and newer come with php-fpm pre-installed, to ensure you are using the brew version you need to make sure /usr/local/sbin is before /usr/sbin in your PATH:

  PATH="/usr/local/sbin:$PATH"

You may also need to edit the plist to use the correct "UserName".

Please note that the plist was called 'homebrew-php.josegonzalez.php71.plist' in old versions
of this formula.

With the release of macOS Sierra the Apache module is now not built by default. If you want to build it on your system
you have to install php with the --with-httpd24 option. See  brew options php71  for more details.

To have launchd start homebrew/php/php71 now and restart at login:
  brew services start homebrew/php/php71
==> Summary
🍺  /usr/local/Cellar/php71/7.1.1_12: 345 files, 50.9M, built in 11 minutes 32 seconds

最初に書かれている、

To enable PHP in Apache add the following to httpd.conf and restart Apache:

の通りに、httpd.confを編集しようと、/etc/apache2/httpd.conf を編集しても反映されない。おっかしいなぁと思って、以下のコマンドをたたいてみた。

$ which httpd
/usr/local/bin/httpd

てことなので、/usr/local/etc/apache2/2.4/httpd.conf を編集して無事完了。

メール添付が生き残る道

ビジネス用途でのメールって、何かと添付ファイルをつけたがる。本文に書けばいいことまでメール添付にしたがる。zipにパスワードつけてまで暗号化したがる。

ということで、ダメなITの代名詞っぽい添付ファイルだが、以下の点で用途が残りそう。

セキュアなファイル送信

今どきのGoogleやMSのメールシステムは、送受信が暗号化されている。だからセキュア。

DropBoxやGoogleDriveは、「インターネットに公開しちゃう」リスクがあるけど、メールの受信箱はそうそう公開されない。ということでセキュアなファイル送信の仕組みとしてはまだまだ残りそう。

履歴付きのファイル送信

ちゃんとした会社ってメールのログをとってる。だから誰がいつ送ってきたかってのが辿りやすい。直筆の手紙ほどではないにせよ、履歴がとれている。複数サーバで辻褄もあわせれるから証拠能力が高い。

スマホでファイルの受け取る手段

スマホだと、PCと違って、ブラウザからファイルダウンロードしてフォルダ管理してってことがすごく面倒。だけどメールならどんなファイルでも添付で受け取れる。その後プレビューできるかどうかは、スマホ次第だけど、PDFの添付くらいは見れちゃう。さらにそのメールを転送すれば、スマホからどこかしらにファイルを送信もできる。

機械が受け取る手段としての添付

ガラケー時代のブログも添付ファイルで画像を送っていた。システムもメールの添付ファイルくらいは別にパースできちゃう。

下手すりゃローカルファイルより検索性が高い

お行儀よくないのだけれど、メールの方が時期とメールアドレスで添付ファイルが探しやすいということがある。gmailなら添付ファイルの中まで検索してくれる。まぁ便利。

リードオンリー

メール添付は編集できないのが面倒なのだが、リードオンリーという価値はある。ローカルファイルに置いたあとにリードオンリーにするのって結構面倒。

migration がそんなにありがたくない

RailsというかActiveRecordというか、今どきのモダンなORマッパーには、migrationという仕組みがある。

データベースのテーブル定義を、sql文で作るのではなく、プログラミング言語で定義できる。select や updateがRubyでできるなら、create tableやalter tableもRubyで書いちゃえばいいじゃないという発想。しかも履歴管理ができるから、戻すことも可能。これはユートピア

しかしながらどうも言うほど登場シーンがない。以下のようなケース。

既にテーブルがある

100%Rails完結するならいいんだけど、Javaのシステムが使ってるテーブルの管理画面をRailsで作るとかって、全然ありえる話。その場合って、もうmigration が要らないのです。「有るべき姿」ではないのだが、RDBが事実上のインターフェースファイルみたいになって、サブシステム同士を結びつけているケースもある。ActiveRecordeのモデルの裏方ではなく、もはやRDBがインターフェース。思想としては間違いなんだろうけど、RailsSQLのどっちが「世界共通言語?」って問いに対しては、SQLが勝ってしまう。

デプロイのタイミングと、alter table のタイミングが違う

Rubyのソースで一括管理すると、ソースのリリースとテーブル定義の変更が、「せーの」でできて、超美しいように見える。だけど本番ではなかなかそういうことしない。DBの定義ってソースのリリースよりも前に、テーブル定義をかえーの、ちょっとしたデータ変換をおこないーの、旧ソースでも新ソースでもどっちでも行ける状態にして、新ソースをドーンとリリースという形が多い。

結局ゴリゴリに直でDBをメンテすることになる。

テーブル定義は地味にエンジン依存が激しい

「utf8mb4 migration」 とかでググるといっぱい事例が出てくるんだけど、DBが定義する新しい目(といってもかなり前から実装されているmysqlの型)が、migratiion には長らく対応していなかった。ORマッパーそのものがDBエンジン依存を排除できるのがいいのところなのだが、実際には4バイトUTF8もネット上ではちらほら居ている。いわゆるUNICODE絵文字が保存したかったら、migration 使えない。

大人の読書感想文

Twitter上では時々読書感想文について言及されているのを見かける。読書感想文があるから本がキライになるのだとか、読書感想文で求められていることがわからないとか、基本的には「読み」「書き」の両面で、学校教育に対して不満を持ってる人が多い印象を受ける。

読書感想文のコツみたいなのも流れてはくるが、そのコツにしたがって作られた読書感想文のサンプルをなかなかみない。

大人になって読書感想文を書くとどうなるのかということを実験してみたいと思う。

あたし彼女を読んで

山本ゆうご

ケータイ小説というジャンルがある。ガラケーの時代に流行した。ケータイで書いてケータイで読むというスタイルだ。書き手も読み手も若い。「あたし彼女」は、第3回日本ケータイ小説大賞の大賞をとった作品だ。ケータ小説ブームの終盤である2008年の作品であり集大成といえるだろう。

ケータイ小説は、ちゃんとした小説に比べると、書き手もプロではないことも多く、日本語としてなりたってない点も多い。そもそもケータイのメールやブログでコミュニケーションをとっている延長線上なのだから、無理に小説の体裁を取る必要もない。しかしそれが通じるのは、ケータイでのコミュニケーションが読み書きの中心である若い女性のコミュニティでのみ通じることであり、部外者からは煙たがられている存在だと認識していた。本書もその一つとして色物扱いで読んでみた。想定通り書き出しから作者の知的レベルの低さを感じる。

まず、文章としてなりたってない。文節という概念さえない。「あたし」「アキ」「彼氏?」「まぁ」「当たり前に」「いる」「てか」「いないわけないじゃん」「みたいな」。この調子で文章が進む。小説として読もうとする人を遠ざけている。ケータイ小説という特性上、私小説の体裁が多いのだが、作者の知的レベルさえ疑いたくなる。こうやって、この小説は読者に不快感を与えながら進んでいく。

ケータイ小説と言えば、女子高生くらいが主人公であることも多いのだが、本作品の場合、主人公は23歳の女性であるというところも痛々しい。単に不快な言葉遣いをするというだけでなく、「23歳にもなって」この精神年齢であるということが恐ろしいのである。

基本的には、この知的レベルの低い主人公アキのモノローグで小説は進んでいく。バカなことばかりしている主人公を読者は蔑んで読み進めていく。しかし、アキはある日恋をする。恋をして初めて自分の感情を言葉として出すようにある。そこで初めて、アキの言葉づかいが変わり、この小説自体の文体が変わる。

やられた。

ケータイ小説特有の不自由な日本語」という世間からの印象を逆手にとって、作者も主人公も蔑まれるポジションからスタートするという「演出」だったのだ。携帯小説の歴史の中では一回しか使えない手法だろう。

気がつくと、知的レベルの低い主人公が恋を通じて成長するというストーリーに引き込まれている。主人公のアキは料理だってできなくても作りたいと思えるようなってる。何よりも自分の感情を表現しようとしている。マイナスからのスタートだが、成長しようとする人を相手に私達は応援はせずにはいられない。本作品をまとめてしまうと、下の下の女の子が下の上になるだけのサクセスストーリーなのだが、世界の中のその小さな出来事を部外者である私達が心から応援できるような構成になっている。

アルジャーノンに花束をという小説がある。知的障害をもつ主人公の日記で物語が進んでいく。この作品も、主人公の知的レベルがそのまま日記の文体に現れることで、読者を引き込んでいく。後から見れば、そういう手法を使っているだけなのだが、ケータイ小説という分野で出会ったことで大きく足元を救われた気分だった。

ケータイ小説ブームのピーク時には書店の文芸ランキングの大半がケータイ小説の書籍化であり、横組み左開きの小説が書店にも並んでいた。今では一時のブームは過ぎ去ったが、書き手と読み手が満足する形で売られてはいる。ケータイ小説特有の文体もこなれてきて、読者に驚きを与えるということもなくなってしまった。もはやそういうライトな小説として世間に受け入れられたと言ってもいい。その中で「あたし彼女」は、ケータイ小説という分野が世間には完全には認められてなかった時代のマイルストンとして記録していい。歴史として読んでおくべきだと思う。