for Startups Tech blog

このブログのデザインを刷新しました。(2023/12/26)

【フォースタ テックブログ】タグの自動予測について。STARTUP DBに機械学習を組み込んだ話【前編】

f:id:forStartups:20211025162928p:plain

はじめに

こんにちは。テックラボの松原です。

先日(2021年3月18日)に、「STARTUP DB サービスリニューアル & ENTERPRISE β版リリース」をしました!

 

startup-db.com

「国内スタートアップエコシステムのキャッシュフローの総量を増やす」というプロダクトミッションのもと、国内スタートアップとエコシステムビルダー、それぞれの信頼できるパートナーとの出会いを創出することを目指して、今回のサービスリニューアルを行いました。

サービスリニューアルでは、下記の機能が利用できるようになっています。

  • フリーワード検索機能
  • タグ検索機能
  • ENTERPRISE β版

※「 ENTERPRISE β版」について
スタートアップエコシステムにおける事業会社、投資家を中心としたエコシステムビルダーの方々と、国内スタートアップ、それぞれが信頼のできるパートナーとのマッチング機会の創造をサポートする機能です。

タグについて

上述しているように、リニューアルしたSTARTUP DBでは、「タグ」という概念が加わっています。

リニューアルしたSTARTUP DBをお使いの方はお気づきかと思いますが、タグが企業やサービスの説明文の下に付けられています。

以前のSTARTUP DBを使われていた方は、「あれ??付いていたような?」と、思われるかもしれませんが、以前のSTARTUP DBに付いていたのは「カテゴリ」です。
リニューアルに伴い、「カテゴリ」を廃止し、今回から「タグ」という分類を行なうようにしました。

STARTUP DBでの「カテゴリ」と「タグ」の定義の違いは、後ほど説明します。

「タグ予測機能」について

エンドユーザーには、今のところ関係のない機能です。

STARTUP DBのデータは、プログラムで自動的に収集している情報もありますが、人の手でこつこつと入力していっている情報が大半です。

完全に自動化してしまわないのは、人的に行う部分を挟むことで、データの品質を保つようにしているからです。

そして、タグ(前カテゴリ)の付与は、そんな人的な作業が大きくかかる作業でした。

企業名、企業の説明、企業の役員、企業への投資、企業が提供するサービス等、企業に関する様々な情報を確認し、これらに適したタグを100以上あるタグの中から選び出すのは、それなりに骨の折れる作業です。

タグ予測機能は、そんな運用の作業を改善するために、実装した機能です。
(今後、この機能をどのように展開していくかは、まだ未定です)

カテゴリ廃止の決断

前STARTUP DBで使っていた「カテゴリ」は、以下の図に示すように、ツリー構造で、企業のサービスに紐付くデータ設計になっていました。

そのため、「医療」カテゴリで「AI」というサブカテゴリを使いたい、でも「農業」カテゴリでも「AI」というサブカテゴリを使いたい、というような要望を満たすためには、同じ名前のサブカテゴリを用意せざるを得ませんでした。

また、検索も「カテゴリ」→「サブカテゴリ」という検索を行うように画面が設計されていたため、横串な検索を素直に行えない状態にありました。

もちろん、力技でもできなくはないですが、リニューアルに伴い、データの構造を見直し、自由度の高い検索を簡潔に行えるようにしましょう、ということで、「カテゴリ」を取っ払い、「タグ」という、多対多の形を取れる仕組みにする、という決断がされたわけです。

タグ予測(機械学習)を実装する決断

タグの実装が決まってすぐは、タグ予測を実装するなんて話はもちろんありませんでした。

タグの実装を進めながら、一方で、どのサービスにどのタグが紐付くのか、それらを一覧にしていく作業の中で、「まだ、あと、8,000件…」と、時間を掛けたにも関わらず、出来高が乏しく…「今の作業だけでなく、今後の運用も考えると、自動でタグが付いてくれる仕組みがいるんじゃないか」という、我らがPMのお言葉により、タグを自動で付ける仕組みをつくってみましょう…!となったわけです。

方針設定

STARTUP DBは、サービスをローンチしてから約3年の月日が経ち、内部のデータも相当のものになっています。

ただ、データがいかに溜まってて、学習をさせる材料があろうと、すべてのタグを、狂いなく、人間が想定するとおりに、完璧に付けることができる程、(少なくとも私は)機械学習での精度を保証できないので、「管理画面でレコメンドが行われるようにする」という方針を立てさせてもらいました。

はじめにのおわりに

長い長いはじめにでしたが、この記事では、そんな「タグ予測」を、どのように実装していったかをお話していこうと思います。

仕組み

現在、この下に記すような構成で、タグ予測を行っています。

タグの予測

現在、タグの予測はこのように行われています。

①運用ユーザーが管理画面で、「タグ予測」ボタンをクリックします。

②企業のサービスの説明文が、アプリケーションサーバー(Flaskで稼働)に送られます。

アプリケーションサーバーは、タグの一覧をマスタから取得し、タグ一覧と、分かち書きされたサービスの説明文を、SageMakerで作った推論用のエンドポイント(MLホスティングインスタンス)に送ります。

④MLホスティングインスタンスは、学習済みのモデルを用いて、タグと、分かち書きされたサービスの説明文をベクトル化し、それらのリストを、アプリケーションサーバーに返します。

アプリケーションサーバーは、説明文のベクトルをクラスタリングし、各クラスター毎に平均合成したベクトルの算出を行います。その後、コサイン近似を用いて、平均合成したベクトルとタグのベクトルの近似値を求め、近しいベクトルのタグを管理画面に返します。

もっとSageMakerに寄せられる部分もあるんじゃないかと思う構成ですが、検討を行った時は、アルゴリズムの日本語対応の状況や、使いたい種類のアルゴリズムがないなど、いくつかの課題に引っかかり、このような構成になりました。

これも詳しい話は後ほど。

学習モデルの作成

MLホスティングインスタンスで使っているモデルは、以下のようなフローで生成しています。

Wikipediaから学習を行うための圧縮されたデータを取得し、解凍します。

②解凍されたテキストの分かち書きを行い、ストレージに保存します。

③SageMaker上で分かち書きされたテキストを用いて、学習を行い、ストレージにモデルを保存します。

こちらの具体的な話は、後編にて。

検証開始

「企業で」機械学習を始めるとなった場合、まず、何から行えばいいのでしょうか?

このタグ予測の開発では、以下の優先順位で検証を進めていきました。

1. コグニティブサービス検証
学習済みのモデルが組み込まれており、値を与えると結果が返ってくる、機械学習のサービスを利用できるかどうか検証する。
2. 提供されているアルゴリズム検証
提供されているアルゴリズムを用いて学習を行わせ、モデルを作成し、そのモデルを利用して値を与えると結果が返ってくる仕組みを作り、想定の結果を得ることができるか検証する。
3. 独自でアルゴリズムから開発
目的に合致するアルゴリズム自体を開発し、学習を行わせ、モデルを作り、そのモデルを利用して値を与えると結果が返ってくる仕組みを作り、想定の結果を得ることができるか検証する。

今回の記事のミソになるのは、「企業で」というところだとも思っています。

優秀な機械学習のエンジニアは、やはり単価も安くはありませんし、社内にほいほい生まれてくるわけでもないので、「運用していく」ということを考えると、(インフラもそうだと思いますが)可能な限りマネージドなものを利用していくのが基本的には、是なのではないかなと思います。
(もちろん、会社のビジョンや、サービスの内容にも左右されるとは思います)

そういった理由で、タグ予測の検証を、上記した順に従って進めて行きました。

コグニティブサービス検証

昨今、AWSGCPもAzureも、その他あらゆるサービスも、ある程度のことは、機械学習の知見がなくても、お手軽にできてしまうような機械学習のサービスを出しており、ゴリゴリ頑張らなくても、目的さえ合致してしまえば、できてしまったりします。

例えば、AWSの場合、以下のようなコグニティブサービスが提供されています。

  1. Amazon CodeGuru(コードレビュー)
  2. Amazon Rekognition(画像解析・動画分析)
  3. Amazon Fraud Detector(偽アカウントオンライン不正の検知)
  4. Amazon Comprehend(テキスト内のインサイトや関係性を検出)
  5. Amazon Comprehend Medica(Amazon Comprehendのサービスを医療向けに特化したもの)
  6. Amazon Textract(画像化された文書からテキストとデータを抽出)
  7. Amazon Translate(テキスト翻訳)
  8. Amazon Transcribe(音声認識
  9. Amazon Polly(テキストを音声に変換)
  10. Amazon Lex(チャットボット)
  11. Amazon DeepComposer(GANによる作曲)※専用キーボードが必要
  12. AWS DeepLens(動画解析)※専用ハードウェアが必要
  13. Amazon Forecast(トレーニングデータから時系列予測モデルを作成)
  14. Amazon Personalize(トレーニングデータからパーソナライズと推奨のモデルを作成)

タグ予測においては、「単語や文章から、マッチするタグを見つけ出す」という処理を行いたいので、コードレビューや音声変換のサービスを利用する必要はないというのは言うまでもありません。

コグニティブサービスの説明に、さっと目を通した感じでは、「4. Amazon Comprehend」と、100歩譲って「14. Amazon Personalize」が使えそうかな、というアタリを付けて、この2つの検証をまず行いました。

Amazon Comprehend

AWSの説明を引用すると、「機械学習を使用してテキスト内でインサイトや関係性を検出する自然言語処理NLP)サービスです。機械学習の経験は必要ありません。」というサービスです。

2019年の11月にプレスリリースで日本語が追加された旨が記されており、もしかすると使えるのではという予感のもと検証を開始しました。

結論。目的とは得られる結果が、絶妙に合致しませんでした。

このサービスは、文章内の単語が人名なのか、数量を表すものなのか等の、各フレーズの属性を分析してくれたり(Entity)、文章内の主要なキーワードは何なのかを見つけてくれたり(Key phrases)、文章の感情分析をしてくれたり(Sentiment)するのですが、これらの結果を利用して、タグを導きだす…というのがどうにも難しいなと…

例えば、上の画像は某サイトのHTMLのTEXTに対して、Entitiesを実行した結果ですが、確かに、それぞれのフレーズのTypeは分かります。

ですが、このQuantity、OrganizationのようなTypeが分かったところで、如何にしてタグへと置き換えて行くか、私の頭では繋がらなくて…断念。

Key phraseならば、出てきたKey phraseとタグをマッピングさせて、想定と近しいことができるのではと思ったのですが…

何か、そうじゃない。

与えるデータが悪かったのは、もちろん、そうなのですが、文章の主要なワードがでてきたところで、文章全体を表すワードを出せるとは限らず、結局タグとの紐付けで、もう一段階何かしらロジックが必要になるなと、こちらも…断念。

他にも、Amazon Comprehendの中には、「Custom classification」という機能があり、学習データを用意して、モデルを作成することで、独自の解析を行うことができるようなるのですが、これは日本語の対応がまだできておらず…

上の画像にあるとおり、タグとテキストの学習データさえ用意すれば、うまくできるかなと思ったりもしたのですが、言語の壁はどうしようもないところでした。

できたとしても、フレーズとタグの分類はできるかもしれませんが、文章とタグの分類はできなさそうですし、これも…断念。

Amazon Personalize

AWSの説明を引用すると、「Amazon.com がリアルタイムのパーソナライズされたレコメンデーションに使用するのと同じ機械学習(ML)テクノロジーを使用してアプリケーションを構築できます。ML の専門知識は必要ありません。」というサービスです。

ECサイトの商品のレコメンドと同じようなロジックで、タグ予測もできないかと考え、検証を行ってみたわけです。

結論。インプットさせるデータがうまく合いませんでした。

というのも、レコメンドを作成するために、下の画像のような、データの定義が必要になります。

つまり、文章のような非構造なデータのインプットがそもそもできないので、今回のデータとは合わないということになります。

私自身、レコメンドの開発に関わっていたことがありましたが、商品の購入履歴やユーザーの行動履歴など、構造化されたデータをその時も使っていましたし、非構造なデータでレコメンドを行うためには、全く違うロジックが要りますよねぇと…断念。

検証の結果

GCP、Azureなどのコグニティブサービスも試してはみましたが、同様に、日本語未対応が問題になったり、結果やインプットが合わないなど、タグ予測をコグニティブサービスで行えるようにするのは、現時点では難しいなと判断し、次の検証を進めることになりました。

提供されているアルゴリズム検証

提供されているアルゴリズムと曖昧な書き方をしましたが、今回利用を検討したものは、Amazon SageMakerに組み込みで提供されているアルゴリズムです。

Amazon SageMakerは、AWSの説明を引用すると、「ML 専用に構築された幅広い一連の機能をまとめて提供することにより、データサイエンティストとデベロッパーが高品質の機械学習 (ML) モデルを迅速に準備、構築、トレーニング、およびデプロイするのを支援します。」というサービスです。

つまり、これだけ使えば、機械学習で必要なあれこれがすべてできますよ、というサービスです。

SageMakerは、デフォルトで以下のようなアルゴリズムを提供してくれています。
それ以外にも、AWS Marketplaceから、アルゴリズムを買うこともできるようになっています。

ベクトル化を行う「Object2Vec」もしくは、テキスト分類を行う「BlazingText」が、今回の目的に合致するのではないかと考え、この2つの検証を進めました。

Object2Vec

AWSのブログ(https://aws.amazon.com/jp/blogs/machine-learning/introduction-to-amazon-sagemaker-object2vec/ )の説明を読むのが正確ですが、簡単に例えると、「リンゴ」と「ミカン」をインプットにして、ラベルを「果物」として学習させれば、2つの情報から分類ができるモデルが作成でき、「ラーメン」と「蕎麦」をインプットしてラベルを「1」、「ラーメン」と「リンゴ」をインプットしてラベルを「0」として学習させると、2つの情報の類似度を推論するモデルが作成できる、というようなアルゴリズムです。

画像引用元: https://aws.amazon.com/jp/blogs/machine-learning/introduction-to-amazon-sagemaker-object2vec/

ラベルと2つのインプットが必要になるので、用意するデータはこのようなフォーマットになります。

{"label": 1, "in0": [774, 14, 21, 206], "in1": [21, 366, 125]}

タグ予測の場合だと、以下のような学習を行うことができるかと思います。

① Skip gram(https://towardsdatascience.com/skip-gram-nlp-context-words-prediction-algorithm-5bbf34f84e0cのように、「文」と、「その周辺の文」をインプットとして、「タグ」をラベルにする。
(参考: https://hironsan.hatenablog.com/entry/object2vec-training-by-japanese-dataset
②「タグ」と「文」をインプットとして、ラベルを「0〜1」(類似度)にする。
設定済みのタグと、企業のサービス情報をSTARTUP DBから抽出し、①②の方法で学習させ、検証してみました。

結論。精度が出ませんでした。

Object2Vec自体は汎用性の高い、良いアルゴリズムだと思います。
しかし、単語レベルなら精度も出たかもしれませんが、やはり、文章というのが多様すぎるためか、学習させるデータが圧倒的に足りない、という印象でした。

データをこつこつコツコツ作ってて精度を上げてくことも考えましたが、もっと上手く解ける方法があるのではないかと、他を模索することにしました。

BlazingText

BlazingTextは、word2vecを行う行うアルゴリズムです。

word2vecに関しては特に語る内容もないかなとは思うので、説明はこれだけです。

結論。これを採用してできるようになった、というわけではないですが、最終的にはこのアルゴリズムを全体の仕組みの中に組み込みはしました。

検証の結果

直接的に、企業の情報とタグを紐付けられる都合の良いものはないのだと思い知らされることになりました。
ただ、アルゴリズムが単に合わないということだけではなく、これらの検証をやる中で、目的に対して、データの総量が多いように見えて少ないことも、上手くいかない原因だということが見えてもきました。

STARTUP DB内部のデータだけで学習用のデータを作って推論させるというのは、少し無理があるのだと。

推論を行わせるためにどういうデータを準備すべきか、少ないなら少ないでどういうロジックを組めばいいか、もう少し検討する必要がありそうだ…という知見を得てからの、次の段階、独自での実装の始まりです。

前編のまとめ

運用を考えて可能な限りマネージドに…と最初に書きもしましたが、そうは問屋が卸してはくれず、完全に満足する結果が得られないから、結局、独自に実装しないといけなくなる、というのが、今なんだろうなと思わされました。

後編では、実際に今動いている仕組みの内容を、詳しく説明していこうと思います。

 

後編に続く

【フォースタ テックブログ】フォースタートアップスでやったチームビルディングを色々と挙げていく

f:id:forStartups:20211025164523j:plain

どうも、村林(@bayashimura)です。今回は私が入社してから開発チームで行われたチームビルディングの色んな手法を参加者の感想とともに紹介していこうと思います。

ドラッカー風エクササイズ

出典:アジャイルサムライ

 

shop.ohmsha.co.jp

10月に速水が参加したタイミングで実施しました。

  • 自分は何が得意なのか?
  • 自分はどういうふうに仕事をするか?
  • 自分が大切に思う価値は何か?
  • チームメンバーは自分にどんな成果を期待していると思うか?

というのをチームメンバーが各自答えて、チームメンバー同士の相互理解や期待値のすり合わせを促進します。

今回の実施では追加の質問として

  • 他のチームメンバー(各個人)に期待することは何か

というものも付け加えております。これはジョハリの窓で言う秘密の窓を開くだけではなく、盲点の窓を開くこともチームビルディングにおいて重視しているからです。新しく参加したメンバーに関しては期待値のすり合わせ、今まで一緒に活動していたメンバーに対してはフィードバックの作用が望めます。

ジョハリの窓とは

自己には「公開されている自己」(open self) と「隠されている自己」(hidden self) があると共に、「自分は知らないが他人は知っている自己」(blind self) や「誰にも知られていない自己」(unknown self) もあると考えられる。

これらを障子の格子のように図解し、格子をその四角の枠に固定されていないものとして、格子のみ移動しながら考えると、誰にも知られていない自己が小さくなれば、それはフィードバックされているという事であるし、公開された自己が大きくなれば、それは自己開示が進んでいるととる事が出来るだろう。

Wikipedia より引用

実際に実施した際には

  1. ホワイトボードに枠を作っておく
  2. 各々上記の質問を書いておく(まだ貼らない)
  3. 一人ずつみんなに説明しながら貼っていく
  4. 最後に発表しているその人に期待することをみんなが説明しながら貼っていく

というスタイルで行いました。

参加したメンバーの感想はこちらです

相手が得意だと思っていること,バリューを発揮しようとしていることと,周りが期待していることのギャップを認識できると,作業を分担するときのコミュニケーションの取り方により気を遣うことができるので重要だと思った
やっぱり個々人何が得意だと思っているのか自分の言葉で説明を聞けて面白い
自分が武器だと思っているもの、自分が大切に思っていることを周囲に無理なく伝えられるのでとても良い
 

16personalities

画像引用元:https://www.16personalities.com/country-profiles/japan

 

www.16personalities.com

いわゆる性格診断です。

深い自己開示や期待のすりあわせにはつながりませんが、時間をかけずにパッとできるのでお手軽に出来ます。
どちらかと言うとこれを実施し、共有したあとのコミュニケーションに役立てそうです。

各自上記のウェブサイトで答えてそれをSlackで共有するという形で実施しました。

参加した人の感想はこちらです

楽しいし,自分で読んでて当たっていると思う
とても細かくて正確なんだろうけれど,ちょっと長いので結局チームの他の人のパーソナリティを記憶できてない
個々人が勝手にできるので、会社全体など大きい枠組みでやると効果的かも。話をしたことのない人に対して「論理型なんですね、僕も論理型なんですよ」などといったコミュニケーションの糸口に使えそう

自己紹介LT大会

今年の2月にホさんが加入したため、自己紹介を兼ねてLT大会をしました。
単純に5分くらいで自分紹介するLT大会をしたというだけです。
各々の個性が出るようにフォーマットは特に指定しなかったところ
甲斐(@MeguruKai)の見たことないクオリティの宣材写真が出てきたり藤井(@yutafujii)が全編に渡りジントニックの作り方に終始したりとツッコミどころにあふれる会になりました。
とても楽しかったです。

ちなみに私の発表資料はこちら。

参加したみんなの感想はこちらです。

仕事以外の分野の話をたくさん聞けて、純粋に楽しかった。大切にしている価値観や、考え方に大きな影響を与えた経験など、広く人生に関わる話は、なかなか普段の中で聞くことができない。
自己紹介とはいえ、型式に囚われず様々な角度で発表していたので非常に面白かったです。個人的には発表のフォーマットを決めてなかったフランクな取り組みが良いと思っていて、発表内容のピックアップや進め方も含め、自己紹介になっていた気がします。また、純粋にチームメンバーを違う側面をみることができなたので、メンバー個人への興味もあがりましたねー
フォーマットと内容が自由だったことで,その部分にも個性が出た気がしており,初めて開催したからこその面白さがあった気がする。結果的には詳細まで記憶できないけれど、その人その人にキーワードが結び付けられるだけでもとても有意義だったと思う
自己紹介を改めてするというのは良いですね。会社にジョインしたタイミングが違うので、日が浅い人にとっても知るきっかけが出来ますし、逆に「今まで言ってなかったけど伝えておきたい」みたいなことも改めて伝えられるので、チームビルディングによいなと思いました!

webox values card

画像引用元:https://wevox.io/valuescard

 

井原(@tossy_yukky)が買って持ってきたので実施しました。

 

wevox.io

カードに「友情」「愛」「本能的」など価値観にまつわるカードが書かれており、それを引いたり捨てたりすることで自分自身の価値観を表す5つのカードを集めるというゲームです。

やり方としては以下の通り

  1. カードを切り、1人5枚ずつ配る
  2. 残ったカードは全て伏せた状態で中央に置く
  3. カードを引く順番を決める
  4. 順番になったら「山」または「テーブルの上」にあるカードから1枚カードを引く
  5. 手元にあるカードの中から自分の価値観に一番遠いカードを捨てる
  6. 次の人に進み、カードの山がなくなるまで4〜5を繰り返す
  7. 残った5枚のカードを使い、自分の価値観を参加者に説明する

ルールブックより引用

5人くらいが適正な人数かなと思い、うちでは2回に分けて実施しました。
一度目はシンプルに上に書かれたルール通り実施し、二回目は「誰がどんな価値観を捨てたかが面白い」ということに気付き、麻雀のように自分が捨てたカードは自分の前においていくようにしました。

 

個人的に面白かったのが藤井が「愛」と「友情」と「幸せ」を捨てて、最後に残った手札に「遊び心」が入っていたことと
竹内(@manbo34)がCTOの戸村(@KenjiTomura)の目の前で「計画」「努力」「勝利」をバンバン捨てていたことです。

楽しみ方ですが捨てる時に捨てるカードを宣言すること(e.g. 私は家族を捨てます)と、それに対して周りがやいのやいの言うと盛り上がります。

参加したみんなの感想はこちらです。

カードきれい,楽しい
5枚に絞るのが難しく,重要なもののなかで優先度をつけるのでそこに価値観が現れて興味深いし自分の思考整理にもなった
プレイ中に相手が捨てるカードを見て、強く相手に興味を湧いた記憶があります。愛(家族?)や幸せを捨てる人の残しているカードは何なんだとw中だるみせず、最後の結果確認まで楽しかったです。」
似ているがニュアンスが異なる言葉が出てくるので、自分の価値観表現として、この言葉が本当にベストか考えるキッカケになりました。

無礼講ースター

画像引用元:https://yonasato.com/column/teambeerding_bureiko/

よなよなエールで有名なヤッホブルーイングが出している(いた)チームビルディング用、ビアコースターです。
ビアコースターなので対面での飲みの場での使用を想定されていますが、リモート飲みでも、飲みの場じゃなくても使用可能です。

ルール

  1. 親はテーマコースターの山札から1枚引き、読み上げます
  2. 親はお題にYES,NOコースターで答えます。回答が見えないようにビアグラスで隠します。
  3. 親以外のプレイヤーは親の回答を予想し、YES,NOコースターで答えます。これもビアグラスで隠します。(親にガンガン質問してもOK)
  4. 親以外のプレイヤーが一斉に回答をOPEN!時計回りに自分の回答理由を話します。
  5. みんなが話し終わったら、今度は親がYES/NOコースターをオープン!
  6. 親は自分の理由に一番近い回答者に、テーマコースターをプレゼント。

これを親役が一周するまで繰り返し、コースターの枚数が一番多い人の勝ち!

https://yonasato.com/ec/product/burei_coaster/より引用

このコースターはみんながそれぞれその人に対する印象を述べるっていうのが自己開示だけではなく他人から見た自分を教えてもらえるというのが良いですね。
これもジョハリの窓で言うと、秘密の窓の開放だけではなく、盲点の窓の開放が含まれています。

現在は販売がされていないみたいなので、もしやりたかったら周りの人で持っている人を探してやりましょう。
それか私に声かけてもらえればやりますのでお気軽にお声がけください。

感想です。

意外な嗜好性がわかる。絶対この人はこう!って思ってたのに実はそうでもなかった。ずぼらだと思ってたのに意外とマメだったり
フォースタ祭りの打ち上げで使いました!10人くらい人数がいる中でも、全員が参加でき会話しつづけられるコンテンツだった気がします!
(これはかなり前に全社イベントで使用された時の感想ですね。私の入社前)

以上で紹介は終わりです。

世の中にはこれ以外にもたくさんチームビルディングの手法がありますので、これからも色々と探してやってみようと思います。

あ、そうそうフォースタでは良いチームで良いプロダクトを作りたいエンジニアを募集しています。
是非ご興味あれば下のフォームから応募してみて下さい!

【フォースタ テックブログ】検索におけるユーザーのニーズに合わせてElasticsearchをチューニングした話

こんにちは、主にサーバーサイドを担当している速水です。

社内向けプロダクト「タレントエージェンシー支援システム(SFA/CRM)」では、検索エンジンとしてElasticsearchを採用しており、最近、検索機能の大きな改善を行いました。今回はそれに伴って、Elasticsearchに関するTIPSを紹介していきたいと思います。

タレントエージェンシー支援システム(SFA/CRM)とは

tech.forstartups.com

タレントエージェンシー支援システム(SFA/CRM)は、RailsAPIサーバーとして機能し、Vueでフロントを構成する設計となっています。一部、erbで記述された部分もありますが、直近手を入れている機能については、APIを介してフロント分離をしっかり行っております。この記事では、RailsAPI開発におけるElasticsearchに関する部分を紹介します。

データ型の見直し(Text型→Keyword型)

Elasticsearchで文字列を扱う場合、Text型またはKeyword型、どちらかを使用すると思います。Text型とKeyword型の違いは、データを格納する際に、Analyzerによって単語に分割され、分割された単語ごとにインデックスが構成されるかどうかですが、これまで使用していたText型では、分割によって検索結果が曖昧になりすぎ、困るシーンがありました。例えば、「Rubyエンジニア」を検索した際に、「Ruby」と「エンジニア」に分解されてしまうことで、Ruby以外のエンジニアもヒットしてしまう、といった状況です。

そういった分割をせずに格納、検索するために、データ型をText型からKeyword型に変更し、検索ワードが"完全一致"したらヒットするようにしました。

indexes :all_resume_contents, type: 'text', analyzer: 'kuromoji_analyzer'
indexes :all_resume_contents, type: 'keyword'

検索結果でのハイライトの実現

検索結果でヒットした箇所のハイライトを行うため、options[:set_highlight]を指定することで、highlightが返却されるようにしました。

filters = @search_definition[:query][:bool][:filter]
...
...(filters.pushやset_sort_query)
...
set_highlight if options[:set_highlight]
__elasticsearch__.search(@search_definition)


def set_highlight
  @search_definition[:highlight] = {
    fields: {
      "**": {}
    }
  }
end

Elasticsearchのhighlightは、wildcardを利用すると全文が返ってくるため、ハイライトを中心に前後40文字と...(省略記号)の形式に、APIを生成する際に加工しました。

copy_toによる検索対象フィールドの集約と返却フィールド

Elasticsearchではcopy_toという機能で、検索対象フィールドをまとめることができます。検索対象のフィールドを少なくすることで、検索スピード向上が期待できます。
もともとresumeというインデックスは、Nested datatypeを使っていました。all_resume_contents単体で検索するより、file_idやnameなどをまとめて検索した方が効率が良いため、copy_toでall_resume_contentsを指定します。

ただ、開発を進めていたところ、all_resume_contentsでヒットした際に、そのフィールドが返却されないことに気付きました。調べていくと、copy_toはあくまでindexed documentであり、source documentではないようです。検索にヒットした際のフィールドや値を使用したい場合は、storeオプションをつける必要がありました。

indexes :all_resume_contents, type: 'keyword', store: true
indexes :resume, type: 'nested' do
  indexes :id, type: 'integer'
  indexes :file_id, type: 'keyword'
  indexes :name, type: 'keyword'
  indexes :content, type: 'keyword', copy_to: 'all_resume_contents', index: false

case-insensitiveの対応

大文字と小文字を区別しないことを、ケース・インセンシティブ(case-insensitive)と言います。今回、データ型の見直しを行ったことで、Rubyrubyや、HTMLとhtmlの検索結果が異なる、ということが発生してしまいました。Text型の時はAnalyzerで吸収されていた部分ですが、Keyword型に変更したことで発生しました。Keyword型ではAnalyzerが使えないので、代わりにNormalizerを使用します。

www.elastic.co

Normalizerには、char_filterとfilterを定義することができ、今回は大文字と小文字を区別しないようにするため、filterでlowercasesを指定しました。Normalizerはインデックス、検索時の入力、どちらにも適用されます。

indexes :memo, type: 'keyword', normalizer: 'lowercase_normalizer'

analyzer: {
            kuromoji_analyzer: {
              type: 'custom',
              tokenizer: 'kuromoji_tokenizer',
              filter: %w[kuromoji_baseform pos_filter greek_lowercase_filter cjk_width]
            },
            ngram_analyzer: {
              tokenizer: 'ngram_tokenizer'
            }
          },
          normalizer: {
            lowercase_normalizer: {
              type: 'custom',
              char_filter: [],
              filter: ['lowercase']
            }
          }

いかがでしたでしょうか。シーンはかなり限られるかもしれませんが(笑)、Elasticsearchを使った検索機能の開発をするときの参考になればと思います。

今回の検索機能の改善は、フロント、バックエンドそれぞれ細かくタスクを分解し、チームが一丸となって取り組んだものでした。いざ結合して検索してみると、想定と異なる結果が表示されることもありましたが、上記のような解決法を取りながら、1つ1つ対応して完成した機能は、まさにチームでつくりあげたと言えます。

フォースタートアップスではエンジニアを募集中です。チームで協働するスタイルが向いている方は、是非ご応募ください!

【フォースタ テックブログ】社内で実践中!ふりかえりを続けるためのコツ

どうもむらばやし(@bayashimura)です。皆さん「ふりかえり」してますか?ふりかえり挫折しますよね?今回は挫折しがちなふりかえりを続けるためのコツを書いていきます。

この記事は技術書典10で発売された『forstartups tech book 1』のふりかえり再入門から抜粋、一部加筆しております

techbookfest.org

まだみんな前のめりじゃない時にファシリテータを交代制にしない

ファシリテータを一人がやり続けることは、大抵の場合アンチパターンとして捉えられがちです。私もふりかえりのファシリテータがずっと固定されていることには否定的です。しかし物事を新しく始める時に誰か一人、それも情熱を持っている人が引っ張っていくのは大事なことです。

早期にファシリテータを交代制にすることは、ふりかえりにモチベーションもオーナーシップもない人間がファシリテータをやらされることに繋がります。その結果ふりかえりのクオリティは下がったり、もしかしたら開催されないかもしれません。

ふりかえりをこれから始める方、途絶してしまっていたけど再びやろうとしている方はまずあなたが続けるところから始めましょう。あなたが会議を設定し、あなたがチームメンバーを呼び寄せ、あなたがファシリテーションして、あなたがメンバーからのフィードバックをもらいましょう。そういった日々を積み重ね、チームがふりかえりに前のめりになってきた時に初めてファシリテータを譲りましょう。それまではファシリテータを交代制にするのはおすすめしません。

一定のリズムで行う

先に時間を押さえましょう。もしスクラム開発をしているのであれば、スプリントの最後の時間などがいいかもしれません。そうではない方々も、1週間に1回や2週間に1回などの固定の時間を取りましょう。すぐ埋まる会議室を押さえ多忙なチームメンバーのスケジュールを押さえるのにこれだけ簡単な方法はありません。

誰かが思いついた時や開発の節目など固定でないタイミングで行うことは、ふりかえりを開催するハードルを上げます。開催の日時に融通が聞かせられてしまうため、全員が参加できるタイミングをファシリテータが調整する羽目になり労力がかかります。ファシリテータがスケジュールを調整するのではなく、参加者がスケジュールを調整する方向に仕向けることで負荷が分散し継続して開催される可能性が高くなります。

色々なふりかえり手法を試してみる

ふりかえりの種類はたくさんあります。またその性質もそれぞれ違います。チームをポジティブにするふりかえり。チームの問題を発見するふりかえり。チームの目線を合わせるふりかえり。色々なふりかえりを試すことで、チームはふりかえりの多様性を実感します。そうなると次のふりかえりを試したくなり、チームはふりかえりに前のめりになります。そのうちチームメンバーが新しいふりかえり手法を提案してくるかもしれません。もうふりかえりはチームに浸透しましたね。

厳しさより楽しさを重視する

ふりかえりは、その性質上、チームに発生した目を向けたくないような事実に目を向けます。そのため反省会や責任の押し付け合いみたいになりがちで、ふりかえりが嫌な行事に思えてきます。
またふりかえりは「チームの悪いところを直す」という方向に向きがちですが、過度な解決思考は良く言えばチームの規律を正しますが、悪く言えば息苦しく高圧的な雰囲気を生みます。

ふりかえりでチームのマインドをポジティブな方向に仕向けましょう。「このチームの凄いところはどこですか? 」「このスプリントのヒーローは?」 褒められて嫌な人はいません。気恥ずかしいし、自己啓発臭くて嫌かもしれませんが一度やってみましょう。

ネガティブなフィードバックの倍のポジティブなフィードバックを言いましょう。面白いジョークを言いましょう(面白くないのはダメです)。ダメダメな自分たちがちょっとでもマシになるためのアイディアではなくグレートな自分たちが更にグレートになるためには何をしたらいいかを考えましょう。そうすることでチームはポジティブになり、ふりかえりの場が盛り上がります。もうふりかえりを楽しみに一週間を過ごすチームの出来上がりです。

ふりかえりをふりかえる

ふりかえりをしていると白熱して時間を使い切ってしまいがちですが、最後に5分くらい残しておきましょう。そこでふりかえり自体をふりかえることをおすすめします。

何故『ふりかえりをふりかえる』ことで『ふりかえりが継続できる』かというと、ふりかえりを推進している人は孤独で不安です。まだチームにふりかえりが定着していない時などは尚更です。みんなの貴重な時間を使ってふりかえりが盛り上がらない時、次のふりかえりを設定することはみんな の邪魔になるんじゃないかという思いがよぎります。

そんなときは何が必要でしょうか。フィードバックです。参加者は顔に表しませんが、とても有意義だったと思っているかもしれません。ふりかえりのふりかえりで参加者がどう思っていたかを 引き出します。フィードバックを貰えれば後に繋げるのは簡単です。良いフィードバックを貰えれ ば続ければいいし、良くないフィードバックが集まればやり方を変えましょう。どう変えればいいかもフィードバックの内容に含まれているはずです。

ふりかえりが毎回盛り上がりすぎて時間がない場合(タイムマネジメント頑張って!)は、会議室の出口に楽しさと 役立ち度合いの2軸のグラフを作りそこに一言とともに付箋紙を貼ってもらう方法があります。また会議が終わったあとに、slack でコメントを求めてもいいでしょう。どんな方法でも良いです。 フィードバックをもらいましょう。それがふりかえりをすすめる人の活力になります。

早いうちにふりかえりの効果をチームに実感してもらう

チームを巻き込む以上、そしてチームが合理的な時間の使い方を求める以上、あまり効果が感じられない会議体は自然となくなっていきます。つまり、ふりかえりを継続する上で大事なことは「チームのみんなにふりかえりの効果を実感してもらう」ことになります。早いうちにふりかえりの効果をチームに実感してもらいましょう。

もしあなたがふりかえりのファシリテートに自信がない場合は、時間をとってしっかりと準備をしましょう。もしくは近くにふりかえりのファシリテートに長けている人がいれば最初のうちはその人にお願いしましょう。これは身も蓋もない言い方になってしまいますが、ふりかえりの価値を知らないチームメイトはあなたの成長を待ってはくれません。最初のうちは持続的なやり方でなくても良いので、まず価値を感じてもらい、そこからチームメイトと一緒に歩んでいくのがオススメです。

 

今回はふりかえりを続けるコツについて書きました。
先月発売した技術書典の同人誌の方ではふりかえりの型などに関しても書いているため、ご興味があれば是非読んでみてください!

また、フォースタートアップスではエンジニアを募集中です!
ふりかえりをして成長していくチームで働きたい方は是非ご応募ください!