Taste of Tech Topics

Acroquest Technology株式会社のエンジニアが書く技術ブログ

【イベントレポート】PRODUCT LEADERS 2021に参加してきました!

TorrentioVideoの開発に携わっている、3年目MLアプリケーションエンジニアの@yktm31です。

7/9(金)に開催された、PRODUCT LEADERS 2021というイベントに参加したので、レポートしたいと思います。

japancpo.org

イベント概要

PRODUCT LEADERS 2021は、Ken Wakamatsuさんが立ち上げた、日本CPO協会が主催するイベントで、
「日本企業をプロダクトの力で強く進化させる」というミッションのために開催されました。

SalesforceAdobe、AtlassianなどのCPO、プロダクトマネージャーの、 プロダクトづくりにおける考えやマインド、意思決定やノウハウがなんと無料で聴けるというイベント。

全部で約9時間になるイベントで、一つ一つのセッションの密度が濃くとても刺激的でした。
全部を網羅するのは難しいので、本記事では特に印象に残ったセッションを3つほど取り上げたいとおもいます。

全体の概要を知りたい方は、ハヤカワカズキさんのまとめをぜひ読んでみてください

印象に残ったセッション

Keynote CPOとは - CEO/CTOとの働き方 (Pratima Arora)

Pratimaさんは、Atlassian社でPM(プロダクトマネージャー), GM(ジェネラルマネージャー)を経験し、 現在はChainalysis社でCPOとして働いている方。

PratimaさんはCPOについて、乗り物に例え、以下のように説明していました。

  • なぜその目的地を目指すのか
  • 目的地では何をするのか
  • なぜ私たちが、他の誰かではなく、その目的地に行くのか
  • 同じ方向に向かっている船と、自分たちはどのように違うのか

つまり、CPOに求められるのは、ビジョンと戦略掲げること、それを元に帆を調整し前に進めること(=実行力)。

エンジニアである自分は普段、How(どのように目の前を解決するか)にコミットしています。 ですが、プロダクトリーダと同じ方向を向くためにも、プロダクトリーダが考えるWhy/Whatを理解していくことが重要だな、と感じました。


他には、顧客との関係、UXとの関わり方、多様性に対する考え方、チーム構築などの話をされていました。
その中でも特に印象に残ったのは、最後に話されていた、「最終的にはすべて人」ということ。

Pratimaさんは、少人数のチームから数百人規模のチームへ拡大した経験もある中、
「自律的で責任感のあるチームを作ること」が、ビジョンを元に前に進むために重要だと学んだと語っていました。
「PMだけでは何もできない」とも言っており、良いプロダクト作りは、 良い組織・良いコミュニケーションの中から生まれるのだ、と実感がこもった重みを感じました。

プロダクトチームをリードする人材育成 (Marcus Torres)

ServiceNow社でGeneral Managerを勤めるMarcusさんによる、PMの育成・チーム構築の話でした。

Marcusさんが言っていた、「プロダクト・マインドセットという言葉が、特に印象に残りました。

「プロダクト・マインドセット」とは、Marcusさん曰く、ソフトウェアに限らず物理的なものについても、
「その製品の目的はなんなのか」「何を達成しようとしているのか」「どうすればより良くなるのか」というプロダクト視点で見ること。

Marcusさん自身のエピソードとして、とあるホテルのシャワーノブが非常に使いづらかった時、
「人が使いこなせないものは、自分なら選ばない!」と思ったそうです。

このように、身の回りの有形・無形の製品に対しする姿勢から、その人がプロダクトを些細なもの、と考えているのかどうか見えてくるそうです。 そして、この「プロダクト・マインドセット」は本からでは学べず、偽れないもの。
エンジニア出身のPMや、MBA出身のPMがいて、それぞれの視点があるが、この「プロダクト・マインドセット」は、共通的に重要なことだとMarcusさんは語っていました。

f:id:yktm31:20210709232108p:plain

実際にMarcusさんは採用面接の場で、
「ある物理的な製品について自分の意見と、それをどうやって改善するのか」
ということを、候補者に聞いているそうです。


自分の胸に手を当て、、、出来ていないなと思わされました。
開発の中で、バックエンド・フロントエンド両方担当していますが、 特にフロントエンドの開発では、「使い勝手」を考え実装する、というチャンスを多くもらってます。
フロントをやる以上、UIデザインの知識がないといけないかな、と思っていましたが、 スキル的な面だけではなく、「プロダクト・マインドセット」を持つことの重要性を学びました。

新規開発とプロダクトマーケットフィット (Geoff Baum)

Adobe社の新規事業のリーダーを経験し、現在はAcceldata社でマーケティングを統括するBaumさんのセッション。

よりビジネスサイドの話題が中心で、Adobe社で新規事業を立ち上げたときのエピソードや、PMF(Product Market Fit)について話されていました。

その中での、Photoshop Expressについてのエピソードが面白かったです。
PhotoshopLightroomという製品がある中で、写真家ではない人のモバイルでの写真編集という市場を開拓。 まず最初にターゲットのニーズを満たすためのアクセシビリティを考え、iOSアプリをリリースしてPMFを検証。 どこでどんな機能を使っているのか、編集した写真を有料で保存、印刷したりするのか、などさまざまなメトリクスを分析し、
ユーザに価値が届いていると判断した時、次のGo-to-Marketのための施策を打つ。

プロダクトを立ち上げから、顧客のニーズを検証、プロダクトのスケールのために動いていく。 プロダクトマネージャーは、プロダクトのCEO(ミニCEO)と呼ばれることもありますが、 まさにプロダクトの成長にコミットするという、プロダクトマネージャー的なエピソードだと感じました。
パワーポイント上で作ったアイディアを、1000万ドル以上の収益にまで成長させた経験があるというBaumさんの、経験に裏打ちされた解像度の高い話がとても面白かったです。

最後に

このイベント登壇していたのは、最先端のテック企業で、 複数のプロダクトをマネージし、複雑な意思決定をしてきた熟練のCPOやPM。

たかだか2,3年のSWE経験しかない自分には、難しい話も正直多かったです。 しかしそれでも、プロダクトに関わる一人でもあり、 どのようにプロダクトを育てていくかという点は興味がある部分。

今回のイベントを通して、世界のプロダクトリーダのマインドセット・考え方に触れることができたのは、 とても刺激になりました。

当社は、ENdoSnipe、そして私が関わるTorrentioVideoという2つのプロダクトを展開しています。 プロダクトを通し、顧客に価値を届け、世の中の課題を解決していきたい。そう思えるイベントでした。

今回初回だったPRODUCT LEADERS 2021、年末に2回目の開催が予定されているそうです。 このような会を、無料で開催してもらえていること、とても有難いなと感じます。
主催の、日本CPO協会の方々ありがとうございます。 (微力ながら寄付させていただきました。) 次回もぜひ、参加しようと思います。



P.S.
記事中、おざきはやとさんのTweetを引用させていただきました。 イベント実況、ありがとうございました。

Acroquest Technologyでは、キャリア採用を行っています。

  • ディープラーニング等を使った自然言語/画像/音声/動画解析の研究開発
  • Elasticsearch等を使ったデータ収集/分析/可視化
  • マイクロサービス、DevOps、最新のOSSを利用する開発プロジェクト
  • 書籍・雑誌等の執筆や、社内外での技術の発信・共有によるエンジニアとしての成長

  少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。

【データ分析】 Kaggle Masterと働きたい尖ったエンジニアWanted! - Acroquest Technology株式会社のデータサイエンティストの求人 - Wantedlywww.wantedly.com

CVのトップカンファレンスCVPR2021へ参加しました

皆さんこんにちは。
@tereka114です。最近、気温が上がってとても暑くなりましたね。

この季節恒例のCVPR2021が先日開催され、今年もリモートで業務後に動画を見たり、論文読んだりして参加していました。
この記事では、CVPR2021の簡単な紹介をしたいと思います。

CVPR2021

CVPRはコンピュータビジョンを扱うアメリカの学会で、6/19(土)〜6/25(土)の日程で開催されていました。
学会の正式名称はComputer Vision and Pattern Recognitionです。

cvpr2021.thecvf.com

昨年からオンラインで開催されており、昨年はリアルタイムで参加していましたが、今年は仕事が終わってから動画を確認するスタイルにしました。
前回のCVPR2020は、COVID-19の影響により急遽オンラインのみとなりました。その影響か、サイトがしばらく遅いことがありました。
しかし、今年はサイトが遅くなることもなく、Workshop/TutorialもYoutubeで配信されて後から確認できるようになっているなど、主催側がオンライン会議慣れしてきた感があります。

タイムゾーンがほぼ異なる私も大きく困りませんでした。

今年の特徴

今年の特徴は次の通りです。
昨年と比べて、論文の提出数が増え、参加者はそのままの傾向です。
参加者がそのままの傾向なのはリモートになったことで論文読むのと変わらない状況になったのが一つの原因でしょうか?

参加者:6800人(前年度同等)
論文数:1600枚/7000枚(Accept/Submission)、前年度比10%増
論文執筆者の国籍:中国、アメリカ、韓国が多い。

相変わらず論文数は多いこともあり、とてもではないですが、読み切れる数ではないので、抽出して動画を見たり読んでいます。
気づいていなかったのですが、公式から6/24に論文検索の素晴らしいサイトができているのでそこをチェックするだけでも楽しそうです。

見つけた論文や著者に類似している論文を探すのに便利なサイト
paper search1

f:id:tereka:20210702140246p:plain:w700

CVの分野ごとの論文を探すのに便利なサイト
paper search2

f:id:tereka:20210702140100p:plain:w700

学会の様子

全体的な傾向

昨年と比べてもより、3Dの技術の傾向は強く出ていました。
また、後述するContinual Learningの分野がOralでちらほらと見られるなど、注目される分野も変わってきたのではないかと考えています。
※今年は残念ながら論文のタグクラウド発表がありませんでした。

サイトでは直接質疑応答ができるビデオ会議や動画のページでテキストでやり取り可能なコンテンツや録画済のInvited Talkなどもあり、
TimeZoneを超えて、自由に参加ができる状態なのが個人的には良い流れだと感じています。

参加したWorkshop/Tutorial

興味ある論文は読み進めている段階ですので、参加したワークショップについて簡単に紹介します。

1. Responsible Computer Vision

sites.google.com

コンピュータビジョンにおける差別や信頼性、データセットの評価などを議論するワークショップです。
大規模なシステムを組んだ際に性別など実際の問題と関係のないような要素で評価されるようなシステムはよくありません。
そのデータセットの評価などで利用できる指標や影響度を消すような手法の紹介がありました。

このような問題は研究よりも、より業務上非常に重要な要素ですので、実際の業務にも活かしたいと思います。

2. Continual Learning in Computer Vision

Continual Learning(継続学習)と呼ばれる分野のWorkshopです。

2nd CLVISION CVPR Workshop

Continual Learningはあるデータを学習させたモデルに対して、新しいデータを継続的に学習させていく中で過去のを忘れないようにするものです。

例えば、TaskAを学習させたモデルAがあり、そこに、新しくTaskBを学習させます。
この 場合にTaskBのみを判定できるがTaskAのデータが判定できなくなる、といった事が多くありました。

これらを工夫により、TaskAとTaskB、どちらも判定できるようにしようといった試みです。
全てのデータを保有するのが難しいが、継続的に新しいデータを学習させ続けるようなケースに便利です。

最後に

昨年よりもリモートでも非常に参加しやすくなりました。
参加者と直に会えない、ポスターの集まりを見れないなど、
リモートならではの課題はまだまだありますが、参加して良い刺激が得られるカンファレンスだったと感じています。

来年はCOVID-19が収まってリアルタイムに参加してみたいです!

Acroquest Technologyでは、キャリア採用を行っています。


  • ディープラーニング等を使った自然言語/画像/音声/動画解析の研究開発
  • Elasticsearch等を使ったデータ収集/分析/可視化
  • マイクロサービス、DevOps、最新のOSSを利用する開発プロジェクト
  • 書籍・雑誌等の執筆や、社内外での技術の発信・共有によるエンジニアとしての成長

 
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。

Kaggle Masterと働きたい尖ったエンジニアWanted! - Acroquest Technology株式会社のデータサイエンティストの求人 - Wantedlywww.wantedly.com

AzureサービスでホストしているAngularアプリをElastic APMで監視してみる

みなさんこんにちは、最近Azure Developer Associate(AZ-204)に無事合格したハヤトです。
これも良い機会ということで、実際にAzureのサービスでアプリをホストしてみるとともに、
Elastic on AzureでAPM環境も手軽に用意してモニタリングも試してみよう、というのが今回の記事の内容になります。

概要

今回はAngular+FastAPIで作った超シンプルなアプリをサンプルとして使用しました。

構成図
f:id:acro_h_nomura:20210627192253p:plain

トップ画面
f:id:acro_h_nomura:20210618025204p:plain

「go to Time」をクリックするとrouterLinkでTime画面に遷移し、現在時刻を取得する「now」APIを呼び出して画面に時刻を表示します。
f:id:acro_h_nomura:20210626002415p:plain

クライアント画面はAngularで実装したアプリをビルドして、Azure Storageで静的Webサイトとしてホスティングしています。
docs.microsoft.com

APIはFastAPIで実装したものをAzure App Serviceとしてデプロイしています。
docs.microsoft.com

※この記事ではアプリの実装およびデプロイ手順の詳細については説明しませんが、上記ページを参考に作成しています。

それでは、作成したアプリをElastic APMでモニタリングするために行った手順を紹介していきます。

Elastic APMの準備

今回はAzure Portalからデプロイを行いました。手順(2021/06現在)をステップバイステップで紹介します。

1. Azure Portalの検索フォームからMarketplaceの「Elastic Cloud (Elasticsearch managed service) 」を検索。
f:id:acro_h_nomura:20210615004901p:plain
今回はキャプチャ内右側の「Marketplace」にあるElastic Cloudを使用していますが、左側の「サービス」にある方ではAzureポータル内でElasticsearchデプロイメントの管理などができる、より統合されたサービスが利用可能です。
※2021/06現在ではパブリックプレビューで、一部のリージョンのみ対応しています。
www.elastic.co


2. 必要情報を入力してリソースを作成。
f:id:acro_h_nomura:20210615005433p:plain

3. リソース作成完了したら「アカウントを今すぐ構成」を選択。
f:id:acro_h_nomura:20210615005628p:plain

4. Elastic Cloudの登録画面が開くので、必要情報を入力して登録。
f:id:acro_h_nomura:20210615005807p:plain

5. 登録完了したらElastic Cloudにログインして「Create deployment」を選択。
f:id:acro_h_nomura:20210615010728p:plain

6. APMを試すので「Observability」を選択。
f:id:acro_h_nomura:20210615010136p:plain

7. 「Customize」を選択すると詳細な構成を設定できます。
f:id:acro_h_nomura:20210627230109p:plain
今回のようなお試しであれば、ミニマムの構成にしてコストを抑えるのが良いでしょう。もちろん後からスケールさせることも可能です。

8. デプロイ完了したらクレデンシャルを忘れず保存。
f:id:acro_h_nomura:20210629094737p:plain

これでElastic APMが利用可能な状態になりました。

f:id:acro_h_nomura:20210629094948p:plain
APMのエンドポイントはデプロイメント画面のコチラから確認できます。後で使用するので手元にコピーしておきましょう。

Angularアプリ側の設定

f:id:acro_h_nomura:20210627193433p:plain
Elastic APMエージェントは様々な言語・フレームワークに対応しており、今回適用対象となるAngularにもパッケージが用意されています。
必要なパッケージをインストールし、ソースコードに数行の設定を追記するだけでAPMが可能になります。
www.elastic.co

公式ドキュメントに従い、以下のように設定を行いました。

パッケージのインストール

npm install @elastic/apm-rum-angular --save

AppModule

import { HttpClientModule } from '@angular/common/http';
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ApmModule, ApmService } from '@elastic/apm-rum-angular';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { AboutPageComponent } from './page/about-page/about-page.component';
import { TimePageComponent } from './page/time-page/time-page.component';
import { TopPageComponent } from './page/top-page/top-page.component';


@NgModule({
  declarations: [
    AppComponent,
    TopPageComponent,
    AboutPageComponent,
    TimePageComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    ApmModule,
    HttpClientModule,
  ],
  providers: [ApmService],
  bootstrap: [AppComponent]
})
export class AppModule {
  constructor(service: ApmService) {
    // Agent API is exposed through this apm instance
    const apm = service.init({
      serviceName: 'elastic-apm-test-client', // Elastic APM側での表示名。
      serverUrl: 'https://example.com/', // APMのエンドポイントを指定。
      distributedTracingOrigins: ['https://example.net'],  // バックエンドAPIのURLを指定。
    });

    apm.setUserContext({
      'username': 'foo',
      'id': 'bar'
    });
  }
}

ApmModuleとApmServiceをimportして、コンストラクタ内でapmの設定を行います。
serverUrlには先程デプロイしたAPMのエンドポイントを指定します。
これによってAngularのルーターイベントがキャプチャされるようになります。
また、distributedTracingOriginsにElastic APMを適用したバックエンドAPIのURLを指定することで、異なるオリジンへのリクエストも分散トレーシングに含めることができます。
www.elastic.co

FastAPI側の設定

f:id:acro_h_nomura:20210627193707p:plain
API側も同様に、公式ドキュメントに従って設定を行いました。
https://www.elastic.co/guide/en/apm/agent/python/master/starlette-support.html

from datetime import datetime

from elasticapm.contrib.starlette import ElasticAPM, make_apm_client
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles

apm = make_apm_client(
    {
        "SERVICE_NAME": "elastic-apm-test-api",
        "SERVER_URL": "https://example.com",
        "SECRET_TOKEN": "SECRET_TOKEN",
    }
)
app = FastAPI()
app.add_middleware(ElasticAPM, client=apm)
app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://example.org"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

@app.get("/api/now")
def get_now():
    return {"now": datetime.now()}

今回はクライアントアプリとAPIが別オリジンなので、CORSの設定が必要になります。
CORSMiddlewareのallow_originsにクライアントアプリのオリジンを追加してあげましょう。
fastapi.tiangolo.com


secret tokenは「APM & Fleet」から確認できます。
f:id:acro_h_nomura:20210629095124p:plain

APMでモニタリング

Elastic APMを適用したアプリを操作するとリアルタイムで情報が蓄積されていきます。
デプロイしたAPMを開くと先程設定した名称でデータが蓄積されていることがわかります。
f:id:acro_h_nomura:20210626015111p:plain

サービスマップもこのような感じで見られます(クライアントとAPIだけなので寂しい…)。
f:id:acro_h_nomura:20210627195447p:plain

クライアント側の「elastic-apm-test-client」を選択すると、router-changeとして/timeのトランザクションがキャプチャされていることがわかります。
f:id:acro_h_nomura:20210626015417p:plain

/timeをクリックするとトランザクションの詳細が確認できます。
Servicesのところにclientとapi両方があるところからわかると通り、先程の簡単な設定だけで分散トレーシングも構成できています。
f:id:acro_h_nomura:20210629095237p:plain

また、API側は「Metrics」からシステムリソースの状態なども確認できます。
Cloud providerとしてazureが表示されており、このあたりの統合もしっかりされていることが伺えます。
f:id:acro_h_nomura:20210627200608p:plain

まとめ

以上、AzureサービスでホストしているAngularアプリをElastic APMで監視してみた際の手順を紹介しました。
実は上記のようなことをやるとなると結局ハマりどころが多いのではないか、ということで検証の目的もあったのですが、公式の情報に基づいてあっさり出来てしまいました。
APMの適用はサクッとできて、本質的な品質の向上に集中できる、というのが良いですね。

Acroquest Technologyでは、キャリア採用を行っています。

  • ディープラーニング等を使った自然言語/画像/音声/動画解析の研究開発
  • Elasticsearch等を使ったデータ収集/分析/可視化
  • マイクロサービス、DevOps、最新のOSSを利用する開発プロジェクト
  • 書籍・雑誌等の執筆や、社内外での技術の発信・共有によるエンジニアとしての成長

 
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。

世界初のElastic認定エンジニアと一緒に働きたい人Wanted! - Acroquest Technology株式会社のデータサイエンティストの求人 - Wantedlywww.wantedly.com

HTTP/2でもモックサーバを活用しよう

こんにちは
maron8676です。
梅雨に入ってじめじめした日が続いていますね。

今回はwiremockを使ってHTTP/2のモックサーバを作成する方法を紹介します。
HTTP/2という比較的新しいプロトコルであっても、
モックサーバを利用してテストコードも書いていきたいですね。

背景

HTTP/2について

2015年にRFCで承認され、最近普及してきているHTTPプロトコルです。*1

HTTP/2には、HTTP/2 over TLS(h2)とHTTP/2 over TCP(h2c)という2つの方式があります。
h2ではサーバ証明書の設定など、HTTPバージョン以外の話も多くなってしまうため、
本記事ではh2cについて取り扱います*2

モックサーバ

本記事では、外部サービスや、他の内部サービスの処理を模倣するサーバを指します。
システム開発では、外部APIと連携したり、内部でサービスを分割して開発することがたびたびあります。

しかし、モックサーバがないと実施したいテストを実行できない問題が発生します。
例えば、図1のような処理をテストする場合を考えます。単純に実行してテストできればよいのですが、
外部APIが利用できない状況だと、図中の処理3といった後続処理で値が使用できずエラーになる状況が出てきます。

モックサーバを利用することで、外部サービスや他の内部サービスを直接利用できない状況でも、システム連携を想定したテストを行えるため、品質の高い状態で開発を進めることができます。

図1 外部APIを利用する処理

モックサーバのHTTP/2対応状況

モックサーバを作成するためのツールとしては以下が挙げられますが、
2021/06/05現在、HTTP/2に対応しているのはWiremockのみとなっています。
そのため、本記事ではWiremockを使ってモックサーバを作成したいと思います。*3

1. Wiremock
2. MockServer
3. Karate

HTTP/2のモックサーバ作成

では、Wiremockでモックサーバ作成を作成するコードを見ていきましょう。

1. Spring Initializrでプロジェクトを作成する
今回は、Maven Project、Packaging JarのJavaプロジェクトを作成します。

2. DemoApplication.javaを書き換える
以下のコードに書き換えます。
createHttpConnectorメソッドをオーバーライドして、h2cのコネクタを追加で指定してあげることによってh2cで通信できるサーバとなります。

3. ビルドしてjarファイルを作成する

mvn clean build

でモックサーバのjarファイルを作成できます。

Wiremock公式からダウンロードできるstandaloneのjarファイル(公式jarファイル)はh2c設定がされていないため、
自分でjarファイルを作成する必要があります。

4. モック動作を設定する
作成したjarは、公式jarファイルと同じようにmappingsディレクトリに配置されたjsonファイルを読み取ってモック動作を変更できます。
公式ドキュメントを見て、必要な動作を定義しましょう。

package com.example.demo;

import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.common.ConsoleNotifier;
import com.github.tomakehurst.wiremock.common.JettySettings;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
import com.github.tomakehurst.wiremock.jetty94.Jetty94HttpServer;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jetty.http2.server.HTTP2CServerConnectionFactory;
import org.eclipse.jetty.io.NetworkTrafficListener;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.ServerConnector;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.util.List;

import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;

@SpringBootApplication
public class DemoApplication implements ApplicationRunner {
    public static void main(String[] args) {
        SpringApplication.run(WiremockHttp2Application.class, args);
    }

    @Override
    public void run(ApplicationArguments args) {
        boolean hasPort = args.containsOption("port");
        List<String> ports = args.getOptionValues("port");
        boolean hasDirectory = args.containsOption("rootDir");
        List<String> dirs = args.getOptionValues("rootDir");
        if (!hasPort || ports.size() == 0 || StringUtils.isBlank(ports.get(0))) {
            System.out.println("--portでポート番号を指定してください。");
            return;
        }
        if (!hasDirectory || dirs.size() == 0 || StringUtils.isBlank(dirs.get(0))) {
            System.out.println("--rootDirでルートディレクトリを指定してください。");
            return;
        }

        int port = Integer.parseInt(ports.get(0));
        WireMockConfiguration configuration = wireMockConfig().port(port);
        configuration.withRootDirectory(dirs.get(0));
        configuration = configuration.notifier(new ConsoleNotifier(true));

        configuration = configuration.httpServerFactory((options, adminRequestHandler, stubRequestHandler) ->
                new Jetty94HttpServer(options, adminRequestHandler, stubRequestHandler) {
                    @Override
                    protected ServerConnector createHttpConnector(
                            String bindAddress,
                            int port,
                            JettySettings jettySettings,
                            NetworkTrafficListener listener) {
                        HttpConfiguration httpConfig = createHttpConfig(jettySettings);
                        HttpConnectionFactory http11 = new HttpConnectionFactory(
                                httpConfig);
                        HTTP2CServerConnectionFactory h2c = new HTTP2CServerConnectionFactory(
                                httpConfig);

                        ServerConnector connector = createServerConnector(bindAddress,
                                jettySettings, port, listener, http11, h2c);

                        return connector;
                    }
                });
        WireMockServer server = new WireMockServer(configuration);
        server.start();
    }
}

動作確認

これで、図1における外部APIを含めたテストをするためのモックサーバを作成できました。
サーバにリクエストをするプログラムの代わりに、curlコマンドでリクエストを送って動作確認してみましょう。

今回はサンプルとして、以下のモック定義を準備しています。
これは公式ドキュメントで紹介されている定義です。
/some/thingにGETリクエストがあった際に、text/plainでHello world!とレスポンスを返します。

{
    "request": {
        "method": "GET",
        "url": "/some/thing"
    },
    "response": {
        "status": 200,
        "body": "Hello world!",
        "headers": {
            "Content-Type": "text/plain"
        }
    }
}

curlコマンドでは --http2 を付けることでHTTP/2でのリクエストとなります。

$ curl -v --http2 localhost:8080/some/thing
*   Trying 127.0.0.1:8080...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
----------1----------
> GET /some/thing HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.68.0
> Accept: */*
> Connection: Upgrade, HTTP2-Settings
> Upgrade: h2c
> HTTP2-Settings: AAMAAABkAARAAAAAAAIAAAAA
>
* Mark bundle as not supporting multiuse
----------2----------
< HTTP/1.1 101 Switching Protocols
* Received 101
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
----------3----------
< HTTP/2 200
< content-type: text/plain
< matched-stub-id: 6fc1a757-7c85-4315-8f4f-cc52b41aadfa
< vary: Accept-Encoding, User-Agent
<
* Connection #0 to host localhost left intact
Hello world!

実行時ログの説明

各部分で何が起こっているのか見ていきましょう。

1. クライアント側からは、Upgradeヘッダにh2cを設定することで、
プロトコルをh2cにアップグレードできないかサーバに問い合わせています。

2. サーバはHTTP/1.1 101 Switching Protocolsを返すことで、
HTTP/2へのアップグレードを行ったことをクライアント側に通知しています。

3. HTTP/2 200 の表示からHTTP/2で通信していることを確認できます。
HTTP/2から、ヘッダのフィールド名が小文字で統一されましたが、
コンソール出力からもcontent-typeのフィールド名が小文字になっていることを確認できます。

---1---などは説明のための目印として挿入したもので、実際に出力されたログではありません。

まとめ

HTTP/2の一方式であるh2cに対応したモックサーバの作成方法を紹介しました。
プロダクトコードと並行してテストコードも実装し、品質を上げていけるとよいですね。
また、未検証のため記載していませんが、Wiremockはh2にも対応しているようなので試してみようと思います。

Acroquest Technologyでは、キャリア採用を行っています。

  • ディープラーニング等を使った自然言語/画像/音声/動画解析の研究開発
  • Elasticsearch等を使ったデータ収集/分析/可視化
  • マイクロサービス、DevOps、最新のOSSを利用する開発プロジェクト
  • 書籍・雑誌等の執筆や、社内外での技術の発信・共有によるエンジニアとしての成長

 
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。

エンジニア募集!100%オンライン、好きな場所で働けます! - Acroquest Technology株式会社のエンジニアリングの求人 - Wantedlywww.wantedly.com

*1:https://www.rfc-editor.org/rfc/rfc7540.txt

*2:主要ブラウザはh2しか対応していないのですが、システム内の内部通信など、h2cを利用する状況もあると考えています

*3:MockServerとKarateでは、HTTP/2対応は提案段階となっています。
MockServer https://trello.com/b/dsfTCP46/mockserver
Karate https://github.com/intuit/karate/projects/3

Shopee - Price Match Guaranteeでゴールドメダルを獲得しました

皆さんこんにちは。
@tereka114です。
GPU熱により、部屋が熱くなってきており、冷房が欠かせません。

先日、Kaggleで開催された「Shopee - Price Match Guarantee」でゴールドメダル(5位/2426)を獲得しました。

※本件のプレスリリースをこちらで公開しています。
www.acroquest.co.jp

この記事ではコンペの概要と当チームの取り組みを紹介します。

概要

ECサイトを運営するShopee社が主催で開催されたECサイトの商品をグルーピングするコンペティションです。
期間は2021/3/8〜2021/5/10の約2ヶ月間に渡り、開催されました。
商品数34250, 商品種別11014に渡る商品のタイトル(テキスト)と画像が与えられ、同一の商品をまとめます。
これにより、ユーザ体験の向上やスパムの排除を実現できます。

テキストと画像といった複数のドメインを利用するといったマルチモーダルのタスクであること、
また、単純に分類や回帰をする問題でなかったことから非常に様々な検証の可能性が見えるのが面白そうと感じて参加していました。

www.kaggle.com

本コンペの評価指標は商品ごとに同一の商品をリストアップしますが、そのリストのF1 Scoreの平均(分母は商品)を算出します。

チームでの取り組み

終了一ヶ月ほど前、私がゴールドメダル獲得圏内に入ったあたりからチームを組みはじめ、最終的にはAhmet, Alvor、私の3人チームで進めてました。
体制としては、Ahmetと私で2つのベースラインとなる手法を構築し、Alvorが特徴量探索(EDA)やFeature Engineeringを進めてました。
チームメンバがそれぞれ得意なところを進めているような感じになりました。

この2つのベースラインの流れは大きく変わりませんが、細部で利用しているモデルは異なります。
利用しているモデルの統合したソリューションは制限時間の都合でできませんでした。
ただ、あえて、最後のスコアのShake対策も兼ねて、全くモデルの異なる2つのソリューションにすることにしていました。

※チームのソリューションはこちらのスレッドに掲載しています。(英語)
www.kaggle.com

課題やうまくいったことを共有しながら進めていたのもあり、日々議論しながら進められたことは学びが非常に大きかったと感じました。

解法

私達のソリューションの流れは次のとおりです。

1. 商品群の中でペアの候補群を作成する。
2. ペアの候補群から候補を絞り、最終的なペアを作成する。

1. 商品群の中でペアの候補群を作成する。

商品群の中からペアの候補群を作成します。
ここでは、タイトルと商品画像を別々に解析しました。
実を言えば、タイトル、商品画像を同時に学習させることも試みました。
しかし、各々から近しいものを候補としたものを最終的に結合するのが最も精度が高かったです。

1-1. 画像解析

画像の検索で利用されるArcFaceを用いました。
ArcFaceは画像検索で用いられる距離学習の手法です。Backboneとしては、次の種類を試しました。

  • ResNet200D
  • EfficientNetB3/B4/B5
  • Swin Transformer
  • ViT

まだまだ畳み込みを用いたもののほうがImageNetよりもデータの少ない場合には精度が高いと思っていました。
今回、Swin TransformerやViTでチームメンバーが精度改善していたのに驚きました。

※ArcFaceの解説はこちらの記事がわかりやすいです。
qiita.com

1-2. テキスト解析

Distilbert IndonesianとMLP+Character basedのCountVector(ngram=1,3)をベースにArcFaceを用いて特徴量を作成しました。
与えられたタイトルの言語は大きくインドネシア語と英語が占めていました。そのため、インドネシア語を学習させてあるDistilbertは特に効果がありました。

huggingface.co

MLP+CountVectorを用いた理由は、タイトル中の数値の違い(同じ種類の商品でも、1000mg, 100mgは商品として異なる)を捉えることでした。
これにより、当時のPublicは0.742->0.756まで向上しました。

1-3. 候補の検索

ArcFaceから得られた中間の特徴量を用いて、類似度が一定のしきい値以上のものを候補としました。
ここで、画像検索で用いられる近しいデータのベクトルから新しいデータを生成するDatabase Augmentation(=Query Expansionと等価)を利用しました。
ベクトルの生成方法は近傍2件(自分含め)の重み付け平均です。データから最低2件以上の同一商品が存在することが確定していたのでこの設定にしました。

ここまでで、すべて導入するとPublic 0.767には乗ります。

※Database Augmentationについては、次のスライドのP23を見ていただくのが良いと思います。

www.slideshare.net

2. ペアの候補群から候補を絞り、最終的なペアを作成する。

上記のペアを用いていくつか特徴量を作り、ペアらしさを算出しました。
このペアらしさの候補群ですが、テキストは合致しているが、画像が違う、画像は同じだが、テキストが違う候補が含まれています。
このようなものを候補から省くことを目的としています。

2-1. XGBoostを用いて、候補を絞る

ペアの候補群から絞るためにXGBoostを利用しています。
2つのペアを使って、特徴として利用したのは次のとおりです。この特徴を学習し、最終的に一致しているか否かのスコアを算出するモデルを構築しました。

  • 画像特徴量の類似度
  • テキストの類似度
  • 画像類似度 + テキストの類似度(単純な加算)
  • 画像類似度 * テキストの類似度
  • FP類似度(学習データの特徴量との類似度を計算し最も近いものの値)
2-2. 凝集型クラスタリング(Agglomerative Clustering)

最後に凝縮型のクラスタリングを利用して同一商品群を求めます。
導入する前は閾値ベースでペアを作成していましたが、これを導入することにより、スコア自体もPublic 0.774->0.778へ向上しました。
最終的には少し画像のサイズを向上させるなどして精度を上げています。

凝縮型クラスタリングそのものに関しては、次のサイトがわかりやすいと思います。
qiita.com

このコンペで学べたこと

  • Transformerベースの画像認識モデル(ViT/Swin Transformer)は各コンペで今後、試す価値があり。
  • BERT+画像モデルは他のソリューションでは成功しているものがあったため、チューニング次第では十分コンペ用途には足りた。
  • 検索で利用されるDatabase AugmentationはECサイトの検索でも効果を示せた。検索タスクだと非常に有効そうに見える。

最後に

ECサイトの商品検索といった非常に面白く、実践的なコンペティションで刺激的な日々を過ごしていました。
非常に勉強になったのでまた面白いコンペに参加しようと思います。

Acroquest Technologyでは、キャリア採用を行っています。

  • ディープラーニング等を使った自然言語/画像/音声/動画解析の研究開発
  • Elasticsearch等を使ったデータ収集/分析/可視化
  • マイクロサービス、DevOps、最新のOSSを利用する開発プロジェクト
  • 書籍・雑誌等の執筆や、社内外での技術の発信・共有によるエンジニアとしての成長

 
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。

【データ分析】
Kaggle Masterと働きたい尖ったエンジニアWanted! - Acroquest Technology株式会社のデータサイエンティストの求人 - Wantedlywww.wantedly.com

cuGraph でページランクを計算したら爆速だった

概要

こんにちは、機械学習エンジニアの古賀です。
最近、人の動きを時系列で解析するためにグラフデータを扱ったのですが、データ量が大きくなると解析に時間がかかってしまい、効率が悪いと感じることがありました。
そんな中、cuGraph という高速にグラフ分析ができるライブラリが あることを知ったので、どれくらい高速なのか、有名なページランクの計算を題材に他のライブラリと速度を比較してみました。

目次は以下です。

グラフとは

グラフ(Graph)とは、頂点(node)と(edge)により構成された図形のことです。
グラフによって、路線図、ソーシャルネットワーク、分子構造など、ものとものとの繋がりを抽象的に表現することができます。
これにより様々なデータを分析することができますが、特にソーシャルネットワークのデータなどはデータ数が大きくなりがちななため、分析の際の計算に時間がかかってしまうのが課題の一つです。

グラフは主に、

  • 有向グラフ (directed graph)
    • 頂点と向きを持つ辺により構成されたグラフ
  • 無向グラフ (undirected graph)
    • 頂点と辺のみにより構成されたグラフ

の2つに分類されます(以下の図)。
またさらにその中にも、各辺に重みがあるもの(重み付きグラフ)、2頂点間に複数の辺があるもの(多重グラフ)などのグラフが存在します。

f:id:acro-engineer:20210430025659p:plain:w600
グラフの種類

グラフを表現するデータ構造には、

  • 隣接行列
    • 各要素が、頂点の対がグラフ中で隣接しているか否かを示す行列
  • 隣接リスト
    • グラフにある頂点または辺を全てリストで表現したもの

などがあり(以下の図)、利用用途によって使い分けられます。

f:id:acro-engineer:20210430030454p:plain:w600
隣接行列_隣接リスト

Python によるグラフデータの分析

上で書いたようにグラフには様々な種類があり、その分析のためのアルゴリズムも多種多様です。そのため、グラフの構築、グラフアルゴリズムの計算、グラフの可視化などを一から実装するのはとても大変です。
Python にはこれらを簡単に行うことができるライブラリがいくつかあり、代表的なライブラリに NetworkX があります。
NetworkX は機能が豊富で非常に便利なのですが、GPU に対応していないため、データ量が大きくなると計算速度が遅くなってしまうのが課題となっています。

networkx.org

cuGraphとは

cuGraph はNVIDIAさんが開発している、GPU でのグラフデータ分析のアルゴリズムを集めたライブラリです。
NetworkX など他の Python のグラフライブラリと違い GPU に対応しており、 GPU 上で高速に処理することができます。

github.com

ページランクとは

グラフデータで利用される有名なアルゴリズムとして、ページランク (PageRank) があります。
ページランクは、Web ページの相対的な重要度を決定し、順位付けするためのアルゴリズムです。 検索エンジンGoogle において、検索語に対する適切な結果を得るために用いられています。
この時、各 Web ページに固有の重要度を表す数値をページランク値と呼び、ページランクアルゴリズムで算出されます。

各 Web ページのページランク値は「重要なページからのリンクが多いページは価値が高い」となるよう、リンク元の Web ページのページランク値を元に算出されます(詳細は以下)。

ページランク値の定義

Web ページ  u ページランク r_{u}^{'} は、

 \displaystyle
r_{u}^{'} = d \sum_{v \in B_u} \frac{r_{v}^{'}}{n_v} + \frac{1-d}{N}

で定義されます。

ここで、 B_u は Web ページ  u リンク元のWeb ページの集合を、  n_v はWebページ  v から出ているリンクの総数を、 N はWeb ページの総数を表します。また、 d は damping factor とよばれ、リンク元の Web ページのページランクによる影響度を調整するパラメータです。0 ≦ d < 1 の間の数で、通常  0.85 に設定されます。

ページランクとグラフ

Web ページのリンク関係は、各 Web ページを頂点、Web ページへのリンクを辺とする有向グラフと考え、隣接行列で表現することができます。
したがって、上で定義したページランク値の式も行列で表現することができ、ページランクは「グラフの各ノードの重要度を算出するアルゴリズム」と考えることができます。

詳細については以下の文献を参考にしてください。
PageRank アルゴリズム およびそれに関連する研究について

検証

cuGraph がどの程度高速に処理できるのか、GPUを使わないグラフ計算のライブラリ NetworkX と比較します。

実行環境

手元にGPUがなくても簡単に試すことができるよう、Google Colaboratory を使用しました。
ランタイムは、ハードウェアアクセラレータをGPU、ランタイムの仕様をハイメモリに設定しました。

cuGraph ライブラリのインストール

Google Colaboratory 上で cuGraph を動かすため、以下のコマンドを実行してください。

!git clone https://github.com/rapidsai/rapidsai-csp-utils.git
!bash rapidsai-csp-utils/colab/rapids-colab.sh stable

import sys, os

dist_package_index = sys.path.index('/usr/local/lib/python3.7/dist-packages')
sys.path = sys.path[:dist_package_index] + ['/usr/local/lib/python3.7/site-packages'] + sys.path[dist_package_index:]
sys.path
exec(open('rapidsai-csp-utils/colab/update_modules.py').read(), globals())

ライブラリのインポート

以下のコマンドで cugraph ライブラリと、検証に必要なライブラリをインポートします。

import time
import cudf
import cugraph
import networkx as nx
import numpy as np
import pandas as pd

データセット

本検証では疑似データとして、ノード10万個、エッジ約2,000万個のグラフデータを作成します。

N = 20000000

df = pd.DataFrame([{'src': np.random.randint(0,100000), 'dst': np.random.randint(0, 100000)} for _ in range(N)]
df = df.astype(np.int32)
df = df.drop_duplicates()
print(f'nodes: {len(df["src"].unique())}')
print(f'edges: {df.shape[0]}'

上記を実行した結果は

nodes: 100000  
edges: 19980133  

でした。

検証内容・結果

公式の README.md によると、cuGraph は cuGraph Graph classes だけでなく、NetworkX graph classes にも対応しているようなので、
今回は、ページランクアルゴリズムだけでなくグラフオブジェクトも cuGraph, NetworkX の両方を使い、計算速度を比較してみました。

1. NetworkX のグラフ、NetworkX のアルゴリズムを用いてページランクを計算

# source (src), destination (dst) ベクトルのペアからグラフを生成する
G = nx.from_pandas_edgelist(df, source='src', target='dst', create_using=nx.DiGraph())

# ページランクの計算時間を計測する
start_time = time.time()
pr = nx.pagerank(G)
print(f'{time.time() - start_time:.3f}秒')

上記を5回実行した平均は、19.158秒 でした。

2. NetworkX のグラフ、cuGraph のアルゴリズムを用いてページランクを計算

# source (src), destination (dst) ベクトルのペアからグラフを生成する
G = nx.from_pandas_edgelist(df, source='src', target='dst', create_using=nx.DiGraph())

# ページランクの計算時間を計測する
start_time = time.time()
df_page = cugraph.pagerank(G)
print(f'{time.time() - start_time:.3f}秒')

上記を5回実行した平均は、11.720秒 でした。

3. cuGraph のグラフ、cuGraph のアルゴリズムを用いてページランクを計算

cuGraph のグラフ(cuGraph Graph classes)作成時の入力には、Pandas の DataFrame ではなく、cuDF という GPU 上で高速に計算できるライブラリの DataFrame を使用します。
cuDF の詳細は以下の記事を参考にしてください。

acro-engineer.hatenablog.com

# Pandas.DataFrame を cudf に変換する
gdf = cudf.from_pandas(df)

# source (src), destination (dst) ベクトルのペアからグラフを生成する
cuG = cugraph.DiGraph()
cuG.from_cudf_edgelist(gdf, source='src', destination='dst')

# ページランクの計算時間を計測する
start_time = time.time()
df_page = cugraph.pagerank(cuG)
print(f'{time.time() - start_time:.3f}秒')

上記を5回実行した平均は、0.009秒 でした。

まとめると以下の結果になりました。

グラフのライブラリ ページランクアルゴリズムのライブラリ 計算時間(5回の平均)[秒]
NetworkX NetworkX 19.158
NetworkX cuGraph 11.720
cuGraph cuGraph 0.009

cuGraph のグラフ、cuGraph のアルゴリズムを用いたときの計算時間は、驚きの速さになりました!これだけ速いと実験もはかどりますね。

計算時間の順番も、
cuGraph のグラフ, cuGraph のアルゴリズム > NetworkX のグラフ, cuGraph のアルゴリズム > NetworkX のグラフ, NetworkX のアルゴリズム
という、予想と一致する内容となりました。

大規模なグラフデータを扱う際に GPU 環境が用意できるならば、cuDF + cuGraph の組み合わせが有力な候補になりそうです。

最後に

今回初めて cuGraph を使ってみましたが、とくに癖もなく使いやすく、かなり高速で驚きました。
ページランク以外にも便利なアルゴリズムがいくつも実装されているので、今後もグラフデータを扱う際には重宝しそうです。

Acroquest Technologyでは、キャリア採用を行っています。

  • ディープラーニング等を使った自然言語/画像/音声/動画解析の研究開発
  • Elasticsearch等を使ったデータ収集/分析/可視化
  • マイクロサービス、DevOps、最新のOSSを利用する開発プロジェクト
  • 書籍・雑誌等の執筆や、社内外での技術の発信・共有によるエンジニアとしての成長

  少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。

【データ分析】 Kaggle Masterと働きたい尖ったエンジニアWanted! - Acroquest Technology株式会社のデータサイエンティストの求人 - Wantedlywww.wantedly.com

Elastic Community Conference 2021に参加してきました!

こんにちは、ノムラです。

Elastic社のイベントである、「Community Conference 2021」が02/27に開催されました。
その速報レポートをお届けしたいと思います。

目次は以下です。

カンファレンス概要

日本時間で27日 0時から始まり、なんと24時間セッションが開催されるカンファレンスです。
今回は事前にCFPの応募があり、その中から選ばれたスピーカーによる発表でした。

内容としては検索、データ分析、クラウド上での活用方法など幅広いジャンルのセッションがあり、レベル感も基本的なものから応用的なものまで多岐に渡ります。

また普段のカンファレンスは英語のセッションが多いのですが、今回は時間帯によってフランス語だったり、韓国語のセッションもあり普段のカンファレンスとはまた違う雰囲気で面白かったです。
今回はそのセッションの中からキーノートと、個人的に面白かったセッションをご紹介したいと思います。

セッションの一覧は下記のURLから確認することができます。
community.elastic.co

キーノート

CEOの Shay Banon 氏によるプレゼンテーションからキーノートが始まりました。
f:id:acro_nomura:20210227161819p:plain:w500

先日発表されたライセンス変更の話や、最近力を入れているクラウドの話が主な内容でした。
ライセンス変更についての詳細は以下のブログを参照ください。
www.elastic.co

また上記の内容以外にも、App Search、ObservabilityそしてSecurityについて7.11で追加された最新機能の紹介も交えたデモが行われました。
特にApp SearchのWebクロール機能はGUI上で簡易に取り込み対象ドキュメントのルール設定や、実際のクローリングを実行することができ便利そうだと思いました。
f:id:acro_nomura:20210227162802p:plain:w500

面白かったセッション

ここからは2つほど面白かったセッションをご紹介します。

Boosting music search results based on popularity and user behavior in Elasticsearch

検索順位を決定するためのスコアリングに関するセッションでした。
f:id:acro_nomura:20210227165234p:plain:w500

Function Score Queryを利用したスコアリングや、編集距離(検索時の表記ゆれ、誤字の是正に利用する考え方)をどう扱うかについて話がありました。
また実際のAPIに落とし込んだ際のデモも実演されました。
f:id:acro_nomura:20210227170853p:plain:w500

スコアリングは検索を扱っていると避けて通れない道です。
そのスコアリングをデモも含めて発表されているので初学者の方におすすめです。

Replacing Google search with Elasticsearch

なぜGoogle Search ApplianceからElasticsearchへ乗り換えたのか、というセッションでした。
下のスライドの通り、ElasticStackは様々な要件を満たしていることが分かります。
f:id:acro_nomura:20210227182444p:plain:w500

以下はそのセッションのまとめスライドです。かっこいいですね。
f:id:acro_nomura:20210227183024p:plain:w500

まとめ

非常に多くの国/ユーザにElaticStackが利用されていることが実感できたイベントだったと思います。
またセッションも多岐にわたっておりElasticStackのユースケースの広さを改めて実感できました。

そして、今回のカンファレンスではElastic社だけではなく、実際のユーザ(エンジニア)の発表も多くありエンジニアとしての刺激を受けられたのも良かったです。

おまけ

今回のカンファレンスのお楽しみ企画としてElasticStack関連のクイズゲームがあったので参加しました。
こういう企画もカンファレンスの1つの楽しみですよね!

ルールとしては10題クイズが出題され、回答の正確さと回答までの速さでポイントが加算される仕組みのようです。
ということで参加してみました。

結果は、、、
f:id:acro_nomura:20210227163145p:plain:w500

9位でした。。。もうちょっと頑張りたかったですね。(問題文が英語だったせい、ということにさせてください)
それでは。

Acroquest Technologyでは、キャリア採用を行っています。

  • ディープラーニング等を使った自然言語/画像/音声/動画解析の研究開発
  • Elasticsearch等を使ったデータ収集/分析/可視化
  • マイクロサービス、DevOps、最新のOSSを利用する開発プロジェクト
  • 書籍・雑誌等の執筆や、社内外での技術の発信・共有によるエンジニアとしての成長

 
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。

世界初のElastic認定エンジニアと一緒に働きたい人Wanted! - Acroquest Technology株式会社のデータサイエンティストの求人 - Wantedlywww.wantedly.com