nakamura244 blog

所属団体とは関係なく、個人的なblog

TFIDFを検索に活かせるかを考えてみた

はじめに

最近自分のmission変更がありまして、検索システムを開発する事になりました。その設計をする中で気になったことを軽くまとめてみようと思います。

別軸で機械学習系をかじり始めました!!

TFIDF?

tf-idf - Wikipedia

まぁその文章の特徴となっている言葉を抽出する手法になるかと思います

なぜ、TFIDFが検索に活かせると思ったのか

きっかけ

makuakeというサイトがありましてね。

クラウドファンディング - Makuake(マクアケ):サイバーエージェントグループ

ここのヘッダーにある検索で 日本酒,保冷というキーワードで検索をして見ます

そうすると下記のような結果になります。

f:id:tsuyoshi_nakamura:20190427214558p:plain

日本酒とは関係のなさそうなプロジェクトがヒットする事はちょっとおいておくとして....😅

日本酒関連のプロジェクトがヒットするのは良いんですが、makuakeでいうと日本酒,保冷で検索するとグッドデザイン賞などで大々的にニュースになった冬単衣のプロジェクトが出てきて欲しい!!と思うわけであります。

日本酒だけのキーワード検索であれば、新着順の日本酒のプロジェクトが検索結果になるのが良いのかな〜

corporate.jp.sharp

www.g-mark.org

改善を考えてみる

機械学習系をかじりはじめてて、TFIDFがシンプルに活用できるんじゃないっと安易に思って、ちょっと試してみることにした。

プロジェクトの文章からそのページを特徴となるキーワードをTFIDFで抽出して、検索された時に活用するよいうイメージ

こんなの作って見た

f:id:tsuyoshi_nakamura:20190427215511p:plain

結果

お米,ひと口,よう,フルーツ,上品,保冷,味わい,新しい,日本酒,本来,段階,甘い,甘み,試み というキーワードを抽出できた

日本酒,保冷というキーワードが抜き出せた。ちょっとイイ感じかも

試した中での課題感など

最後

検索精度が向上する糸口が見えた気がする。まぁ少なくとも検索して結果のscoreに考慮してあげても良いとは思えた

でもプロダクション投入レベルに持っていくのそれはそれで色々あるんだよなーと思いつつお疲れ様でした。👋

社内勉強会で最近やってる機械学習についてちょっとLTした

最近隔週になった社内のエンジニア勉強会でLTした内容をちょっと残しておこうと思います

資料

speakerdeck.com

  • 社内のデータを活用したスライドもあり、一部抜粋版にした
  • なので資料だけをみてもあまりわからない...

なので簡単に書きにリライトする

前提

  • 業務と直接関係の薄い領域に対して業務時間内も多少学習してもokという許しをえて、機械学習をやり始めた。
  • 一ヶ月色々やって見ての一次アウトプットの一つと位置付けしたLTである

まぁ言いたかった事

1.

数式や統計、アルゴリズムと一つ一つを見るととても深いし、難易度がある分野であるのは確か。

だけど、自分のプログラミングを初めて学んだ時のことを思い出して見る。(例えばPHP

php-srcのCの実装やLexing(字句解析)、Parsing(構文解析)、コンパイルなどの知識がないとプログラミングできないかで言うと、そんなことはない。

もちろん、奥深くまで知識を有してプログラミングする人はいるし、理想ではあるけど。

build in されている関数の振る舞いや考え方など最低限の知識を習得して、オブジェクト志向の名の下に規約に沿ったプログラミングをすれば、一応のプロダクション環境にリリースできるレベルのものは作れる。

まさにこのノリ(考え方)と同じで機械学習にチャレンジしてみても良いなと感じたので、チャレンジしているよという事

2.

基本的に学習はひとり旅になる。途中よくこの方向性で良いんだっけって疑問を持つ事がある。

なので適切な評価尺度があるものを取り入れるべき。 -> kaggleに参加する事で補っている

自分の周りにマスタリーな人がいれば良いんだが、いない事のが圧倒的に多い。

自分の今の学習が正しいのかを常に正しくフィードバックしてもらえるものは大切!!

スクールみたいなを受講するのもいいと思うけど、時間場所限らず、自分の好きなペースでやりたいという事でkaggleにした

おまけ

kaggleの世界だと 例えば0.01%改善するとshake upしたりするけど

自分たちの事業ドメインや、会社規模を考えるとその0.01%はそこまでインパクトないなと思ったりする。

もし、現職の事業に取り入れるとしても、規模や影響度も加味しないといけないなと感じている

golangにおけるcopy-on-write (COW)

結論

ない?!と思った

検証

雑にこんなコードがある

package main

import (
    "fmt"
    "runtime"
)

var mem runtime.MemStats

func printMem() {
    runtime.ReadMemStats(&mem)
    fmt.Printf("%d byte \n", mem.Alloc)
}

func main()  {

    v := [9999999]int{}


    var i int
    for i = 0; i < 9999999; i++ {
        v[i] = i
    }
    printMem()

    c := v
    printMem()

    fmt.Println(v[0])
    fmt.Println(c[0])
}

実行すると

- go run test.go

80,115,344 byte 
160,122,064 byte 

すでに変数に代入した段階で実際に値がコピーされている為に利用メモリが増えている

例えばcopy-on-write (COW)の最適化が働いている場合は

例えばPHPとかで同じように下記のテストコードがある

<?php
$a = array_fill(0, 999, "aaa");
echo number_format(memory_get_usage()) . "byte \n";
$b = $a;             // 配列を代入
echo number_format(memory_get_usage()) . "byte \n";

実行すると

- php test.php

323,960byte
324,096byte

誤差は多少あれど、変数に代入しただけでは利用メモリは増えない。

今度は変数に代入した先で値を変えて(writeを発生)やる

<?php
$a = array_fill(0, 999, "aaa");
echo number_format(memory_get_usage()) . "byte \n";
$b = $a;             // 配列を代入
echo number_format(memory_get_usage()) . "byte \n";
$b[1] = 0;           // 代入先の配列を変更
echo number_format(memory_get_usage()) . "byte \n";

実行すると

- php test.php

324,536byte
324,672byte
421,000byte

writeが発生したため、実際に値のコピーをしてからwriteした為、メモリ利用量は増えた。

なので

golangにおいてはcopy-on-writeで裏で最適化してくれはしないようですね。なんとなく頭に入れながらコーディングをしていこうかと思います。

なんでないのだろうか?とか、もっと別の理由であえてないとか、深堀してみたいけど帰ってこれなくなりそうなので一旦ここまでにしとこうかと思う

Go1.12に上げた時のメモ

今の会社のメインで開発しているリポジトリのGoのバージョンを上げた時のメモを残しておこうと思います。検索にヒットして誰かの少しでも役に立てれば幸い

まずはざっくり

Go 1.12 Release Notes - The Go Programming Language

まずはざっくり、リリースノートを眺めて大枠を抑えよう!

基本的には1系なのでGo 1 promise of compatibility in mind.の元に大体は大丈夫だろうなぁーっとなんとなく思っていた。

Go 1 and the Future of Go Programs - The Go Programming Language

んで、大きめの変更で担当のリポジトリに関係しそうなところはModulesぐらいだなと思い作業した。

それでもちょっとコケた部分はあった

そんな大してハマった訳ではないが、気になったところをまとめておく

1. clangコマンドが見つからない問題

Go1.12に上げた後にtestを走らせてみたら下記のようなエラーが出力された。でも結論からいうとGo1.12と関係はないです。自分のマシンの設定の問題でした。

# runtime/cgo
pyenv: clang: command not found

The `clang' command exists in these Python versions:
  anaconda3-4.4.0/envs/xxxx

ちなみにその時のgo envの結果は下記

GCCGO="gccgo"
CC="clang"
CXX="clang++"

特に問題ないはずですよね〜。

なぜか、clangコマンドが見当たらない問題ですが、エラーログからすぐにわかったのですが、自分のマシンでは機械学習関連でPythonを入れています。

しかも、anaconda経由で。

それで.zshrcに下記のようにPython関連の設定を仕込んでいます

export PYENV_ROOT=$HOME/.pyenv
export PATH=$PYENV_ROOT/bin:$PATH
eval "$(pyenv init -)"
export PATH="$PYENV_ROOT/versions/anaconda3-4.4.0/bin/:$PATH"

こいつのおかげでclangのパスが/Users/xxxx/.pyenv/shims/clangとなっていました。

普通は/usr/bin/clangになっているはずです。

致し方ないので.zshrcのexport設定をいちいちいじりながら対応しています。

あまり詳しく追いかけていないけど、anacondaじゃなくて、pyenvの方がうまくあっていないのかも...

pyenv,anacondaあたりでmacローカルマシンで機械学習関連をやっているGopherの方は注意です!!

自分は最近Python関連も積極的にいじるようになって、それ用の環境を整えた所がちょっとバッティングしてしまったという感じです。

2. プライベートリポジトリのgo get

何も気にせずにやると下記のようなエラーが出る by circleci

git fetch -f origin refs/heads/*:refs/heads/* refs/tags/*:refs/tags/* in /go/pkg/mod/cache/vcs/217ea393f42f5804c253aab4ec165a343ea79430ab82e5d628514a79a78c9a53: exit status 128:
    ERROR: Repository not found.
    fatal: Could not read from remote repository.
    
    Please make sure you have the correct access rights
    and the repository exists.

circleciの設定で下記は実施済み

name: "Setting netrc"
command: |
  echo "machine github.com" >> /home/circleci/.netrc
  echo "login ${GITHUB_ACCESS_TOKEN}" >> /home/circleci/.netrc

でもなぜか効いていない

致し方なく、下記のFAQで書かれているgitconfigでの解決法を試したら解決したのでこちらの方法にした

Frequently Asked Questions (FAQ) - The Go Programming Language

まぁsshでの接続のが早いだろうし、良いか😅

軽く感想的なところ

  • module-aware modeはGo1.13からはデフォルトになるようなので、基本的にGO111MODULE=onで動かしている。1.13にあげる時に少しでも楽なように
  • 軽く忘れたけど、開発環境のGOROOT,GOPATHどうするかみたいなやつもう統一されてくるんじゃなかろうか
  • moduleもキャッシュされるようですね.
    • circleciを早くするポイントかな。うちはdeployまでcircleciでやるので割と重要かも
  • さよならdep,vendorディレクトリ👋

ペチコン仙台でちょっと喋った

はじめに

週末に下記のカンファレンスに参加させてもらったので色々と残しておこうと思います

phpcon-sendai.net

お話させてもらった内容

speakerdeck.com

気づけばスタートアップしてから6年目なんだなーと思いつつ色々とまとめたレビューに関する発表資料になります。

おそらくプログラミングのレベルの差関係なく、聞けるものだと思ったし、セッションを聞いて色々と意見や感想を持つ人がいるのではと思ったので私はあえて少し早めにセッションを終えてQAの時間にしようと思っていた。

まぁQAで手が上がらなかったとしたら、色々質問を投げかけて見ようと思っていました。

こういった時間や同じ空間で意見交換できる事が個人的には一番のカンファレンスに行くメリットだと思っているところもあります。

いただいたQAを元にあらためて考えてみた

受託開発の立場だと、こういったレビュースタイルはどう適用すれば良いのか?

もうかれこれ、10年ぐらいは自社サービスをしている会社に所属してまして、その立場目線が持ててなかったです。💦

改めてちょっと考え直してみると、受託の場合でもその期待値がシステムだけでなくて、開発・レビューを通じての情報とかノウハウとかという感じで成果物を定めて契約をするとやりやすいかも?って思いました。ちょっとビジネス交渉必要になりますが。形として残りづらいから難しいのかな...

よい気づきをありがとうございました。

レビューも立派なチームの成果だが、査定にはどう反映されているのか?

当然レビューで得た気づきや潜在的なバグの防止なども成果になるのであれば、査定で考慮されてしかるべきですよね。

レビューでのやりとりを査定で拾う仕組みは現状ありません。このへんは今の所、問題提起もされていないですね。

でもよく振り返ってみると、今のチームメンバーでいうと自分だけでした。正社員は。他の方はみな業務委託契約でした。なので査定って当然正社員だけの話になるので自分が気にしていなかっただけと言うオチですね💦

自分としては、基本的に査定に不満があるわけでもなく(正確に言うと大して気にしていない。正しいと思った事は細かい事は気にせずやってしまうべきスタンス)という感じで過ごしていた為ですね。

ただ、査定面談の時に、このgithubに残っているコメントは良いねというフィードバックをいただいたりするので仕組みはないが、現状の上司はそのへんの価値・成果を汲み取ってもらってると思われます。

結局レビュー中に議論が紛糾してしまったらどう着地するの?

最終的には、テックリードもしくはそのプロジェクトをマネージメントしているPMに判断が委ねられますね。

感情は無くしてフラットにどちらのがメリットが高いのか、今後の戦略に合うのかでちゃんと選択をする理由を持ってジャッチする事が重要なのかなとか思います。 あとはちょっと思うのは、あえて少し冷却期間を置いてからもう一度話すみたいな事をするとみんなが冷静にもう一回話せるかなとも感じています。

レビューの通りやすい人、通りにくい人出て来ませんか?

実際ありますよね。自分も経験があります。

ちょっと振り返ってみると

レビューが通りやすい人の特徴ってその人との関係値で他のプロジェクトで一緒にやった経験から信頼残高がある場合とかエンジニアリングの感覚が近い人なのかなって思っています。

逆にレビューの通りにくい人はエンジニアリングの感覚が遠い人なんだろうなと感じます。どちらが正しいという事ではないです。

こう言うのってすごくありがたい機会だと思います。新しい観点で指摘してくれるからです。自分のエンジニアリングを見直すきっかけになる可能性があります。

長年同じ現場にいてベテラン領域になってしまうとコメントで指摘してくれる機会が少なくなってしまいます。という視点からも逆にありがたい事

でも、プロジェクトを納期までにリリースするのも大事なmissionなのでそうも言っている時間がない場合もあると思います。その際は直接話をするMTGを設定してしまって、そこで直接コミュニケーションをしてしまいますかね。さらに私の場合はslackでやりますかね(オープンなチャンネルで)

そこで率直な議論をして得られた着地をgithubの該当のPRに残せる。詳細の議論はslackのリンクを貼っておく。そうする事で他の人も全てを追える状態にしておくとさらに他のメンバーにも有益な情報を還元できるという感じです。

あとは、事前にリーダブルコードのような内容をなるべく準拠しましょうとか、このデザインパターンにある程度乗りましょうとか、と言うような事をプロジェクトの最初とかに決めておくとスムーズになる部分はあると思います。

新しい技術を導入する際の知見のあるレビュアー不在問題にはどうしている?

当然新しい言語やFW等をいれる際って、知見を持っている人は限られる or いない場合があると思います。その場合当然レビューに困りますよね。

うちではブラックボックステストならぬ、動作検証をするレビューもokとしています。 こう言う正常な叩き方以外にこんな叩き方をしたらエラーログ出たんだが...というレビューです。中身のコードを読まずに、外から色々叩いてみて正常な動作をしているかというレビューです。

だいたいの人が、それをやっているうちにコードにデバッグプリントを仕込んでみて動かしてみたりし始めます。

昔、新人だった頃よく先輩に動くコードをもらって、それを動かしながらどう処理を書いてるんだろうって学習した人は自分だけではないと思います。その思考と同じでこういったレビューを繰り返す事で新しい技術に対しての理解が進みます。(ただ自身で本を読んだり等の自助努力は前提です)

そうした時間を過ごして本来のコードレビューを可能にしていきます。

ちょっと脱線しますが、その世界でのエキスパートを招聘して1日外部講師をしてもらって一気に知見をチームに吸収させる手もありだと思います。

新しいアーキテクチャを導入する主導者でもちょっと不安が残る場合などにこの手の方法を取っています。無鉄砲にプロダクションに投入して事故を起こすより、事前にこう言った事をする事で防止できる事を考えるとどちらがコストを安くつくかという話をプロジェクトをリードしている人には理解してもらう必要はありますが。

最後

前夜祭、懇親会等々色々なところで色々な方とお話できてとても楽しかった。やっぱりエンジニアの横の繋がりは大切だな〜ってつくづく思った。

懇親会のLTが一番楽しいんじゃないか説がちょっとあります。まぁお酒も入るのでってところもあります。

おまけ

カンファレンスは前夜祭や懇親会、2次会等々、食べ過ぎ飲みすぎパターンを何度か経験したので、翌日はおやすみにしてブログを書いてジムにいく日にした。あとは今日はジムいくだけだ。

社内勉強会でPHPについて少ししゃべった

毎週水曜にやっている社内勉強会

資料

speakerdeck.com

先人の資料を拝借させてもらったのでありがたく思っています。

blogにして書く事があまりなかったので雰囲気の写真を上げておく

f:id:tsuyoshi_nakamura:20190116210517j:plain f:id:tsuyoshi_nakamura:20190116210513j:plain f:id:tsuyoshi_nakamura:20181212191503j:plain


あ、でもnginxは最近なんか日本での活動を活発化させようとしてるっぽい感じがしているのでちょっと気にしてたりします。

初日に暇な人です

このツイートが目にしたので書いておこうかと思います。こんな人もいますよ程度にね。

本日、会社的には仕事始めですけど自分は暇です。

一応理由をつらつら書いておく

1. 仕事を作ったらすぐにやってしまうスタイル

そもそも始業時間が何時で就業時間が何時でみたいな感じで仕事をしていないです。

自分は普通の生活をするように仕事をしていくスタイルです。

taskを作れば、空いた時間で手をつけてしまいます。そしてどんな仕事もある程度のチームでやると思うので、taskが終わったらメンバーに共有なり、レビュー依頼をします。

そのレスポンスが来るまでは当然待ちになってしまう。この待ち状態のtaskが増えるとあまりいい事はないのである程度溜まったらやめておきます

私の場合でいくと勝手にmergeなんて暴走はできないのでどうしても待ちになります。

そうすると、持っているtaskがない状態が普通になってきます。

2. 年末年始はみな休みだから基本レスがない

お休み期間なので仕事をしない事は普通だとは思います。

生活するように仕事もする人にとっては年末年始だからと言って大した差はなくて普通に仕事もします。

何なら休みにして旅行に行っている間も数時間仕事をするときもあります。

周りは稼働をしないので、すぐにレビュー依頼のステータスのtaskになります。

なので

初日に暇なんです。

ちなみに

年末年始はどこも混むので休みを取らないけど、年に1,2回は1wぐらい休んで旅行する時はあります。(ただし、混雑が嫌なのでだいたい平日にとる)

そんな時はだいたいそれまでにタスクをこなしてレビュー依頼(当然丁寧な依頼本文を書きます)にしてから休みに入ります。

そうすると休み明けにはレスが溜まってるのですぐに仕事に取りかかれたりします。

でも一番良いのは

会社的に休みの時は、会社とは関係のないtaskなり、仕事をしていれば良いと自分でも思っている。

だけど、自分の性格的に一つのことにハマると最後まで少しでも早くやりきりたい欲が勝ってしまう。

直した方が良いのかは分からないから現状はこんな感じ