(O+P)ut

習うより慣れろ、Practice makes perfect。この言葉をモットーに、Slerで働く若手インフラエンジニアが、学んだ知識を【 (O+P)ut = OutPut 】していく場です。

【Linux】指定した列を特定の単語で検索し、表示する【awk】

タイトルの通りで、grepコマンドを用いると行全体で検索がかかってしまう、それを避けたい時に使うワンライナーが以下となります。

cat ファイル名.csv | awk 'BEGIN{FS=","} $3 ~ /hoge/ {print $0}'

上の場合、csvファイル、つまり区切り文字が カンマ(,) なので field separator を "," としています。カンマ区切りされた行の3列目に hoge という文字列が含まれていれば 行全体を表示することができます。$0 は行全体という意味なので、任意のX列目が欲しければ $X としてください。

以上、かなり短い かつ とても簡単 ではありますが、Google検索で探そうとするとなかなかヒットしなかったので、キーワードをちりばめながら備忘録程度に書いてみました。

【超絶入門】データベースとインスタンスの違い

データベースとインスタンス、二つのキーワードの関わりについて簡単に説明してみます。

よく見る全体像の図は以下のようなものだと思います。(以下、図①)

Oracleのアーキテクチャより抜粋
これをもう一段階簡略化し、ユーザーを入れ込んだ図がこちらになります。(以下、図②)
f:id:mtiit:20170723180955j:plain

では、こちらの図②を軸に説明してみます。

1)インスタンスとは

インスタンスは、データベースとユーザーの中間に位置しており、ユーザーはデータベースを直接操作する代わりにインスタンスを介して操作することになります。インスタンスの中身に関しては、図①にあるように SGA(=メモリ構造) と プロセス群 で構成されています。
細かいことは置いておきますが、インスタンスを介して操作を行うことは、データの安全性やパフォ-マンスの向上につながります。インスタンスは、サーバーにいます。

一つのデータベースには、基本的に一つのインスタンスです。

2)データベースとは

こちらはイメージがしやすいかもしれません。いわゆる、データファイルをはじめとする物理ファイルです。図①にもその他とありますが、データベースに対する変更情報を管理するファイル等々があります。データベースはストレージにいます。

以上が超絶入門です。


以下はおまけです。データベースとインスタンスが1:1ではない例とメリットです。

f:id:mtiit:20170723223913j:plain

これのメリットは、複数のデータベースをより少ないメモリで管理できることにあります。
逆にデメリットとしては、インスタンスの障害がそれに紐づくすべてのデータベースに影響を与えてしまいます。


f:id:mtiit:20170723223923j:plain
これのメリットは、インスタンスの停止等の障害にも対応することができる点にあります。
逆にデメリットとしては、メモリやプロセス等の多くの資源が必要となります。

もちろん、この二つを組み合わせた複数インスタンス→複数データベースもあります。もっと細かい話に関しては、別の記事をご参考ください。

以上です。

【Java】複数画像を元にGIF画像生成

Twitterの話題ワードがどのように遷移しているかをGIFで可視化するという記事ですが、
【R言語】Twitterより取得した話題ワードの遷移可視化 - (O+P)ut
上の記事は文字列から一意の座標を生成するところにフォーカスをあてていました。

今回は、Javaを用いて大量のJPEG画像からGIF画像を生成する手法について紹介します。
というのも、実は海外の方*1が書いたソースコードがネットに転がっていました。
http://elliot.kroo.net/software/java/GifSequenceWriter/GifSequenceWriter.java
特別なライブラリも必要なく、コメントもしっかりと記述されているのでとても参考になります。

ソースコードを見てみると、

ImageOutputStream output = 
new FileImageOutputStream(new File(args[args.length - 1]));

となっています。つまり、引数argsの末端が出力GIFのパス、それ以外は入力画像のパスという仕組みです。
今回はディレクトリ直下の画像のパスを取得し、pathlistという新たな配列を用意してargs代わりに使いました。*2

String path = "hoge"; //画像が置いてあるディレクトリ
File dir = new File(path);
File[] files = dir.listFiles();
String[] pathlist = new String[files.length];
for (int i = 0; i < files.length; i++) {
 pathlist[i] = files[i].toString();
}

あとは、args部分をpathlistに置き換えて実行すれば問題なく稼働します。

timeBetweenFramesMS

という変数で、フレームの切り替わりの時間を管理しているので、そこは適宜変更してみてください。ループするか否か等も変更可能です。

私がGIFを作る時は、"サブリーン"というウェブサイトの"パラパラマンガ"機能をよく使いますが、
プログラムとしてGIFが生成できるというのも、自動化等を考えた際には有効だと思います。
ご参考ください。

*1:Elliot Kroo氏作

*2:dir.listは、取得順序が不明なようです。本来は、きちんと名前順でソート等も必要ですが今回は目視して名前順になっていたのでソートしてないです。

【R言語】Twitterより取得した話題ワードの遷移可視化

Twitterのホットトピック取得については、こちらで紹介しました。
その日、「最も」話題となったキーワードを調べてみる - (O+P)ut

今回は上記記事の手法でホットトピックを取得し、2017/6/17にあったAKBの総選挙の際のトピック遷移を可視化してみました。

話題ワードTop20から、24時間分のTop10を10分毎に表示しています。
大きさは、ランキング上位なものほど文字のサイズを大きくしています。
f:id:mtiit:20170819200700g:plain

この画像を作成するにあたって行った、
文字列 → 数値 への変換について当記事では紹介します。

同じワードは同じ位置に表示させたいため、同じ文字列から同じx座標、y座標を生成する必要があります。
今回は、R言語にて Message Digest 5 を用いました。
パッケージをインストールすると、

> library(openssl)
> md5("hoge")
[1] "ea703e7aa1efda0064eaa507d9e8ab7e"

のように 文字列"hoge"から"ea703e7aa1efda0064eaa507d9e8ab7e"といったハッシュ値が生成されます。

文字列"hoge"からx座標とy座標を生成するために、md5で生成された文字列から[a-z]を抜いて、整数に変換しています。
y座標は、文字列を反転させて(hogeならegoh)同じ処理をしています。

> as.integer(substr(gsub("[a-z]","",md5("hoge")),0,5))
[1] 70371
> as.integer(substr(paste(rev(strsplit(gsub("[a-z]","",md5("hoge")),NULL)[[1]]),collapse=""),0,5))
[1] 78970

あとは、上で取得した座標位置に text 関数 で 文字を貼付けてplot画像を生成しました。
文字の色も、md5の値を使って文字列から一意になるようにしています。*1

一応、ソースコード全文は以下に掲載しておきます。
ひらがなをplotに図示するために par(family="HiraKakuProN-W3") という設定を入れています。

library(openssl)
tweet_mat <- matrix(scan("上位20位がカンマ区切りで記載されているファイルパス",what=character(),sep=","),nrow=20)
par(family="HiraKakuProN-W3")
for (i in 1:144)
  {
  plot(-10,10,xlab="",ylab="",xlim=c(-2.4,2.4),ylim=c(-1.2,1.2))
  for (j in 1:10)
  {
    tweet_x <- 2-4*as.integer(substr(gsub("[a-z]","",md5(tweet_mat[j,i])),0,5))/100000
    tweet_y <- 1-2*as.integer(substr(paste(rev(strsplit(gsub("[a-z]","",md5(tweet_mat[j,i])),NULL)[[1]]),collapse=""),0,5))/100000
    tweet_col <- as.integer(substr(gsub("[a-z]","",md5(tweet_mat[j,i])),0,5))%%8 + 1
    text(x=tweet_x,y=tweet_y,labels=tweet_mat[j,i],cex=(10-j)/5+0.5,col=tweet_col)
  }
  filename <- paste("./hoge/file",i,".png",sep="_")
  dev.copy(png,file=filename)
  dev.off()
}

以上です。

*1:また、気が向いたら md5 での 文字列→数字 の生成部分が乱数のように機能しているのか検証してみたいです。

その日、「最も」話題となったキーワードを調べてみる

Twitterからの情報を取得しながら何かをしようとすると、Twitterと連携するためのOAuth認証を行わなければなりません。
Twitter4J - A Java library for the Twitter APIなどを使えば、もちろん認証周りをスムーズにはしてくれるのですが、やはり認証用アカウントの取得は必須です。

一方で、このようなアカウントが不要でTwitterの情報が使用できるサービスに
Yahoo!検索があり、ここでは最新の話題ワードTop20が表示されています。*1

ここのhtmlを取得すれば簡単に世間の関心等をフォローすることができますので、紹介ついでに少し解析して遊んでみたいと思います。

過去の記事同様 【Linux】wgetで桂離宮の参観可能日を取得する - (O+P)ut
wgetで取得してもいいのですが、今回は jsoup( Java で HTML の解析・編集を行うためのライブラリ)を使ってhtmlを取得しました。

ライブラリを取得し、org.jsoup...をインポートさえ行えば

String url = "https://search.yahoo.co.jp/realtime"
Document document = Jsoup.connect(url).get();
String str = document.html();

たったこれだけの記述でstrにhtmlが入っています。

あとは、htmlの構造を見ながら必要な箇所のみを出力して以下のようにTop20のキーワードを吐くようにしました。*2

java -jar getHotTag.jar 
パラド,グラファイト,ジュリオ,17号,永夢,エグゼイド,飛彩,マーダッコ,リオ,パラドクス,リプログラミング,アンラッキー,界王様,いちか,スティンガー,サンデーモーニング,プリキュア,ポッピーピポパポ,キュウレンジャー,リュウテイオー

これを10分毎に起動して`date +%Y%m%d`.csvファイルに出力し、「その日、最も話題となったキーワード」を調べてみます。
2017/4/23 0:00~24:00 での計144回の検索結果を以下のワンライナーでソートしました。

cat 20170423.csv | awk 'BEGIN{RS=",";ORS="\n"}{print $0}' | awk '{count[$0]++}END{for(i in count)print i","count[i]}' > result.txt

RS=",";ORS="\n"によってカンマ区切りを全て改行にし、count[$0]とすることで連想配列としてカウントしています。

ちなみに、上の出力結果を wc で確認すると

$ wc result.txt 
     265     305    4577 result.txt

つまり、4/23 に「最新の話題ワードTop20」に出てきたワードは265種類だということになります。

この265種類のワードをcountの値でソートして出力した結果はこちらです。

f:id:mtiit:20170423235920p:plain

ぶっちぎりの一位が確認できます。
さて、上位3位はこのようになっています。

1. ナオトインティライミ (count:93)
2. エキシビション (count:43)
2. 不審物 (count:43)

一位に関しては、
f:id:mtiit:20170424000129p:plain
とのことでTwitter上で賑わっているようです(笑)

以上です。

*1:非公開に設定されていない日本語のツイートを主な対象として表示している模様

*2:2017/4/23/10:00あたり

【Java】簡単モザイク生成

これはなんのキャラクターでしょうか。
f:id:mtiit:20170314232445j:plain
どことなく、国民的アニメの主人公に色合いが似てる気がしませんか?

少し前に、モザイクをかけても人間はアニメキャラクターを見破ってしまう というのが話題になりました。
私も同じように、画像を配列と見た時に各行の平均の色を出力することで簡易モザイクを作成する遊びをしてみたのでここに共有します。

Javaでの画像取得は以下のように行います。BurreredImageのメソッドを用いて縦横のサイズも取得可能。

File f = new File("[入力画像のフルパス]");
BufferedImage read=ImageIO.read(f);
int w = read.getWidth();
int h = read.getHeight();

さて、画像の各画素を取り出して平均をとりたいんですが、
BufferedImageでは画素を取得するメソッドgetRGBを用いると、 R G B を8bitずつで表現する以下のような形が返り値となっています。
00000000 00000000 00000000 00000000
なので、R G B をそれぞれ取り出すために

public class Img{
 public static int r(int c){
  return c>>16&0xff;
 }
 public static int g(int c){
  return c>>8&0xff;
 }
 public static int b(int c){
  return c&0xff;
 }
 public static int rgb(int r,int g,int b){
  return 0xff000000 | r <<16 | g <<8 | b;
 }
}

といったクラスを用意しておくと便利ですね。
rgbは、各r,g,bを基に元の値を構成するメソッドです。

画像の各列の画素の平均値の画像を出力するコードは以下になります。

public class Main {
 public static void main(String[] args) throws IOException {
  File f = new File("[入力画像のフルパス]");
  BufferedImage read=ImageIO.read(f);
  int w = read.getWidth();
  int h = read.getHeight();
  BufferedImage write = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
  for(int y=0;y<h;y++){
   int r = 0;
   int g = 0;
   int b = 0;
   for(int x=0;x<w;x++){
    int c = read.getRGB(x,y);
    r = r + Img.r(c);
    g = g + Img.g(c);
    b = b + Img.b(c);
   }
   int n_r = r/h;
   int n_g = g/h;
   int n_b = b/h;
   for(int xx=0;xx<w;xx++){
    int rgb = Img.rgb(n_r, n_g, n_b);
    write.setRGB(xx, y, rgb);
   }
  }
  File f2 = new File("[出力先のフルパス]");
  ImageIO.write(write, "jpg", f2); //jpgで出力
 }
}

最初に見せたモザイク画像の元画像はこちらです。
f:id:mtiit:20170314234708p:plain
両側が黒くなっているのは、透明化している部分の画素が 0/0/0 で 黒と同じだからみたいです。
この辺は、改良の余地ありですね。以上です。

【Linux】wgetで桂離宮の参観可能日を取得する

f:id:mtiit:20170213141405j:plain
この写真は、約1年前に桂離宮で私が撮ったものです。

日本には、桂離宮修学院離宮の二つの現存する離宮があります。*1
これらの参観は無料ですが、事前に予約を行うのが一般的です。詳しくは宮内庁のHP参照。
予約はWebからもでき、例えば桂離宮について見てみますと以下のようにWebで空き人数付参観可能日が確認できます。
f:id:mtiit:20170213142210p:plain
これらの情報を、Webサーバーからファイルをダウンロードするためのコマンドwgetを用いて取得してみたいと思います。

2017年2月現在、上のページのurlは

"https://sankan.kunaicho.go.jp/register/frame/4201?ym=[西暦4桁][月二桁]"

という命名規則となっています。

標準出力に出すためのオプション -O - を使いまして来月(201703)でwgetをしますと以下のようにエラーとなります。※環境によっては証明書の発行者が不明というエラーが先に出る場合があるかとは思いますが。*2

wget -O - https://sankan.kunaicho.go.jp/register/frame/4201?ym=201703<html><head><title>Request Rejected</title></head><body>The requested URL was rejected. Please consult with your administrator.<br><br>Your support ID is

The requested URL was rejected に関してですが、調べてみますと
"ユーザエージェントWgetを排除している可能性がある"
ということが分かりました。宮内庁のHPに関しては、他のページも同じエラーが起きました。悪戯対策なんですかね?
オプション -U "" を用いて明示的にユーザエージェントを空欄に変更してみると、

wget -O - -U "" https://sankan.kunaicho.go.jp/register/frame/4201?ym=201703<html>
  <head>
    <META http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <META http-equiv="Content-Style-Type" content="text/css">
...以下略

といった形で正規のhtmlを取得できました。

あとは、
日付情報↓

<TD width="20" align="center"><B>01</B></td>

参観可能人数情報↓

<img src="/images/false.gif">10:00(0人)

といったような構造になっておりましたので、以下のワンライナーで結果を取り出してみました。
読み方は、3月1日の15:30から2人空いている、といった感じです。

$ wget -O - -U "" https://sankan.kunaicho.go.jp/register/frame/4201?ym=201703 2>/dev/null | grep -B 10 '[1-9]人' | grep -e '[1-9]人' -e '<B>[0-9][0-9]</B>' | awk 'BEGIN{FS="[><]"}{print $5}'01
15:30(2)
02
10:00(1)
15:30(2)
03
09:00(4)
13:30(1)

ワンライナーに関して簡単に説明します。
大部分は 0人 ですので 0人以外のところを grep -B 10 '[1-9]人' で拾います。-Bオプションをつけることで、一致した行から前10行を同時に表示し、日付情報を拾い出しています。htmlを見ますと、日付~参加可能人数が10行毎に繰り返していたので今回はこのようにしています。そして、改めて日付と参加可能人数の情報をgrepで拾い出し、awkで欲しい箇所を抽出しています。今回は、< または > で区切るとどちらも5列目でしたので上のようにしました。

ちなみに、5月だと1日も空いてませんでした。。。
京都に立ち寄る予定がある方は、ぜひ事前に調べてみてください。

*1:修学院離宮にも行きました。どちらもぜひ一度は行ってみる価値ありです!

*2:接続先が信用できる場合では --no-check-certificate を追記ですれば簡易的に対応可能です。