徒然日記

社内ISUCONが開催されていて観覧者用のUIからスコアが上下する様子を見ていたりした。直近開発に打ち込んでいるところもないので参加はしなかったのだけど、逆に観覧者として見ているとエンジニア以外の職種の人にこの様子を伝えてみると面白いかもなと少し思っていた。

そうすることで日頃エンジニアが機能の開発・サービスの開発以外のところのどの部分が気になっていて改善しようとする時間を取りたいと感じているのかというのが少しでも共有できるのではないかと思ったり。まだ具体的にどういったみせかたをするのが、わかりやすいのかといったところが浮かばないが。

昼食に同部署のデザイナーと外に出て何故かARMの話で盛り上がった。

関東地方、台風の影響無かったが北海道・東北方面が心配。

nroongaを使ってデータストアして全文検索するまで

昨日の続き。

繰り返しになるが、解決したい課題と現状は、

  • 数ギガサイズのアクセスログがある
  • 上記に対して数万パターンの文字列それぞれが何回出現するかを数え上げたい

という状況。なので、このログファイルをngroongaを介してgroongaのデータベースを新規作成し、そこに格納してみる。

もちろん事前にGroongaのインストールが必要なのでインストールする。Macであればbrewでインストールすることができる。

$ brew install groonga

で、次に、

  • Groonga DB作成
  • DBへデータを格納するためのテーブル作成
    • 今回はシンプルに1テーブルにbodyという1カラムを作ってそこにアクセスログ1行分を格納する
  • 上記のテーブル中のカラムを全文検索するための語彙表(インデックス)用のテーブル作成
  • テキストファイルベースのログファイルを格納

という上記の一通りの作業は以下のコードで実現できる。

var nroonga = require('nroonga'),
byline = require('byline'),
fs = require('fs');
var db = new nroonga.Database('db/accesslog');
db.commandSync('table_create Logs TABLE_NO_KEY');
db.commandSync('column_create Logs body --type Text');
db.commandSync('table_create', {'name':'LogIndexes', 'flags':'TABLE_PAT_KEY',  'key_type':'ShortText', 'default_tokenizer':'TokenBigram', 'normalizer':'NormalizerAuto'});
db.commandSync('column_create', {'table':'LogIndexes', 'name':'body_index', 'flags':'COLUMN_INDEX|WITH_POSITION', 'type':'Logs',  'source':'body'});
var stream = fs.createReadStream('access.log', { encoding: 'utf8' });
stream = byline.createStream(stream);
stream.on('data', function(line) {
var log = JSON.stringify([
{'body':line}
]);
db.commandSync("load", {'table':'Logs', 'values': log});
});
stream.on('finish', function(){
console.log("Finish parse log file.");
db.close();
});

上記の格納が完了した後*1、実際に格納した情報にたいして全文検索するには以下の様に select のクエリを発行する。limit:0 を指定することでGroongaでは件数のみを取得できるので、例えば今回格納したログファイル中に「Windows」という文字列が何回出現したかということを得たい場合は以下の様な形になる。

var nroonga = require('nroonga');
var db = new nroonga.Database('db/accesslog');
var res = db.commandSync('select', {'table': 'Logs', 'match_columns':'body', 'query': 'Windows', 'limit':0});
console.log(res);
//=> [ [ [ 1869923 ], [ [Object], [Object] ] ] ] 

かなり気楽に全文検索できる状態を作れる。最初スクリプトgrepツールで解決しようと思ったが少し時間がかかりすぎなところがあったので対象を絞ることを考えていたりしたが自分が解決したかったことは解決できそう。

例えばサービスの方針等々を検討する際の数値集めが簡単に行える様にするためにログ基盤を整える等が最も正しい解決策だとは思うのだが、ひとまず何かしらログが残されていれば手元にこういった環境を作って調べてみるのも一つのやり方かなと思う。

参照

*1:ちなみにGroongaのDBとして作られたファイルのサイズは投入したアクセスログのサイズが1.8Gbyteに対して、4.3Gbyteになった。

外は雨なのでnroongaと戯れつつ「やわらなか生命」を読む – 徒然日記

東京は朝から雨。

空いた時間でnroongaと戯れる。

f:id:hideack:20160828103417p:plain:w300

nroongaはNode.js用のGroongaバインディング全文検索エンジンのGroongaをライブラリとして利用できる。よって検索のプロセス自体はNode.jsが担うことになる。

手元にとあるサーバーのログがあって、それに対して対象とする文字列にマッチする行をカウントする的なことをしたくなったのだけど、サイズが数ギガ単位で微妙に大きいのとマッチングしたい対象文字列が多いので、であれば全文検索エンジンに一度該当ログを突っ込んでから多様な条件でカウントさせればいいのではということを試してみている。なんで今、Groongaなのかと問われれば「使ったことがないから」。

案外もしかしたらもっとお手軽ソリューションあるのかもしれないけど、目の前の課題を解決するための方法としてはありなのかなと思う次第。

気分転換するときはやわらかな生命を読む。「シンプルな均衡」という文章が掲載されているのだけど、アンバランスなシステムに関する提言はなるほど感があった。

エネルギーをできるだけ等身大の、生命に親和的な方法で得ること。ヘロンの公式の美しさは、そのシンプルな均衡にある。近代が推し進めてきた方法の美醜が、いまあらためて問い直されているのだと福岡ハカセは思う。

福岡伸一, やわらかな生命 p.48

世の中の万物のシステムは何かしらのエネルギー(経済活動としての対価も含む)を得る目的で運営されている以上、アンバランスな体のまま何かしらを得ることは何事も難しいのかもしれないということを端的に表現した文章だなと思った。

特定単語のGoogle検索順位をSlackなどに通知したりGoogle analyticsに記録したりする

タイトルが全てシリーズ。

google-search-rankというnpmを作った - テノニッキ (@hideack 's diary)というエントリで書いたとおり検索語に対する特定サイトの検索順位を取得できる様なnpmを作ったので弊作のevacの入力として指定できる様にしました。

例えば、

in:
searchrank:
key: "(google custom search API key)"
cx: "(google custom search engine ID)"
site: pickup.calamel.jp
maxPage: 5
format: ":google: 検索語「__word__」 = __rank__位"
word:
- "よしざわ窯"
out:
ikachan:
url: http://*********
join: false
channel: "#hideack"
message: "__word__"

という設定をYAMLで定義してevacに渡すと指定したSlackのチャンネルに

f:id:hideack:20160820214103p:plain

といった具合でSlack通知させることができます。

Slack以外にも出力としてGoogle analyticsへ順位をアウトプットすることもできるので、そうすると検索順位と実際にサイトのPV等をまとめて管理できるのできっと便利。少なくとも自分は便利。

夏休み中に読んだ本

特別遠出する予定もなく、ほぼ自宅で過ごしていたので少し厚めの本も含めて読んでいた。もっと読みたい本があったのだけど夏バテ状態だったのかほとんど横になっている多かった感じもするが読めただけ多少は得たものもあっただろうと思うことにする。

[ECブランディング特集]販促会議2016年9月号はECブランディング特集ということで、とても中身が自分にとっては充実している内容で読み応え合った。なんらかECに関するサービスに携わっている人であれば必読感高い。

確率思考の戦略論 USJでも実証された数学マーケティングの力USJのマーケターとアナリストの人が書いた本でUSJの集客数を拡大させた新アトラクション(ハリーポッターのテーマパーク)の開発を進める際の分析術が書かれていて、恐らく何かしらの対人サービスに携わっている人がそれとなく意識をしていることをロジカルに整理された内容だった。例えば題材と出されていた洗剤の年間購入回数がどの様な分布をするかといったところについて、具体的にどの様な確率分布(=ポアソン分布)になっているかについても書かれていて、直感的にその様な分布になっているだろうなと思い描くことと、数式として表現して考えることでは思考に差が出てきそうだなと自戒。

数式的な表現による考え方以外にもチーム論だったりビジネス戦略の焦点について以下の3つで考える点も非常にシンプルでわかりやすい。

  • 自社ブランドへのプレファレンスを高める (好意度, Preference)
  • 認知を高める (認知度, Awareness)
  • 配荷を高める (Distribution)

徒然日記

特に何をするわけでもなく夏休みを過ごしている。

ふと思い立って夕方、飛行場の近くの公園の丘から飛び立つ飛行機を眺めていた。

すっと現れて滑走路へ着陸していく飛行機はとても綺麗だった。

google-search-rankというnpmを作った

以前紹介した google-search_rank | RubyGems.org | your community gem host のインスパイア。

再発明感あるけどGoogleのCustom search APIを操作するgoogle-searchというクライアントを使って任意の条件で検索をかけて検索順位を取っている。

該当APIで取得した検索結果の情報と検索順位がコールバックされる。

引数で検索ワード, 対象ドメイン, 最大検索結果何ページ目までを走査するかを指定する。

var searchrank = require('google-search-rank');
searchrank.key = '(API Key)';
searchrank.cx  = '(Custom search engine ID)';
searchrank.find("安住紳一郎の日曜天国", "hideack.hatenablog.com", 10, function(rank, result){
console.log("RANK => " + rank);
console.log(result);
});

とすると

RANK => 70
{ kind: 'customsearch#result',
title: '「安住紳一郎の日曜天国」というラジオ番組を毎週聞いている話 ...',
htmlTitle: '「<b>安住紳一郎の日曜天国</b>」というラジオ番組を毎週聞いている話 ...',
link: 'http://hideack.hatenablog.com/entry/2016/04/20/225328',
displayLink: 'hideack.hatenablog.com',
snippet: '2016年4月20日 ... 安住紳一郎の日曜天国 (通称 "にちてん")という番組があって自分は大好きなので毎週\n日曜日の朝10時から聞いているのですが、twitterで まもなくTBSラジオで安住紳一郎の\n日曜天国のお時間。今日はインスタントラーメン研究家 大山即席斎 ...',
htmlSnippet: '2016年4月20日 <b>...</b> <b>安住紳一郎の日曜天国</b> (通称 &quot;にちてん&quot;)という番組があって自分は大好きなので毎週<br>\n日曜日の朝10時から聞いているのですが、twitter��� まもなくTBSラジオで<b>安住紳一郎の</b><br>\n<b>日曜天国</b>のお時間。今日はインスタントラーメン研究家 大山即席斎&nbsp;...',
cacheId: 'Nckg46Amc5IJ',
formattedUrl: 'hideack.hatenablog.com/entry/2016/04/20/225328',
htmlFormattedUrl: 'hideack.hatenablog.com/entry/2016/04/20/225328',
(snip)

といった具合。あぁ、前回調べた時より大分順位下がったな。などといったことが知ることができて便利。

www.npmjs.com

2016年7月に読んだ本を振り返る

先月は11作品。


hideackの本棚 - 2016年07月 (11作品)
powered by Booklog