Sansan Tech Blog

Sansanのものづくりを支えるメンバーの技術やデザイン、プロダクトマネジメントの情報を発信

名刺データ化コストを改善する

はじめまして、DSOC Development Group で開発をしている石畑です。

現在は名寄せチームで、データ統合の機能開発をしています。関連のある名刺データを統合することで、顧客情報を一元管理できるようにしたり、世の中の様々なビジネスデータを収集し、名刺に紐づけることで、名刺の価値を高めることがぼくらの目的です。Ruby(Rails) で開発しています。

RubyKaigi 2019 に参加して、Sansan ブースにも立っているので、ぜひ開発のあれこれについて話しましょう。

DSOC Development Group の取り組み

DSOC は Sansan の「データ」を司る部署です。そのため、「データ」を使ってユーザー価値につながることなら何でもやる所存ですが、現在できていることは大きく次の 3 つです。

  1. 名刺データ化システム(GEES)の開発
  2. データの名寄せ
  3. 人・組織のニュース配信

これらのサービスは、それぞれ 3 - 6 人ほどの小さなチームで開発しています。少人数ながら、Sansan, Eight 全ユーザーに影響を与えられるとても刺激的なサービス開発です。これだけ多くの価値に関われるのが「データ」を扱う DSOC 開発の面白さだと思います。

今回は一例として、以前携わっていた名刺データ化システム(以下、GEES と呼ぶ)で、データ化のコスト削減を行った話したいと思います。

GEES の概要

GEES は名刺を高いセキュリティで、素早く、ミスなく、低コストにデータ化するためのシステムです。今は 10 ヶ国語に対応しています。

スピード・コストを重視すればガンガン自動化していけばいいんですが、そうもいかないのがデータ化精度です。Sansan はデータ化精度 99.9% をサービスとして約束しており、それがサービス価値の土台になっています。 また、本ブログでビジネスネットワークの活用などが紹介されていますが、活用するにはデータが正しくなければ意味がありません。そこで「人」によって高精度なデータ化を実現しています。自動と手動、そこのバランスがとても難しく、GEES 開発の面白いところでもあります。

少しでも自動化の恩恵を受け、手動の効率を上げるために、GEES の内部は自動車の組み立てラインの様に約 20 もの工程(サービス)に分かれています。

データ化フロー
多くの工程を AI と人を組み合わせてデータ化している

これらは全て Rails で開発されており、そのマイクロサービスを連携させるのが AWS の Amazon Simple Workflow Service (SWF) です。 データの状態を見て、簡単にサービスを組み替えられるのが SWF のいいところです。 また、それ以外にも Aurora や ElastiCache, SQS, DynamoDB, Elasticsearch Service などなど、少人数チームで大量のデータを扱うために様々な AWS サービスをフル活用しています。

続きを読む

RubyKaigi 2019に参加します

こんにちは。VPoEの宍倉です。

本日よりRubyKaigi 2019が始まります。そして、今回もRubyKaigiの協賛をしています。

数年前より社内にて参加希望者を募るようになりました。毎年参加者が増え、今年は約20名のエンジニアが参加します。
多様なセッションで学び、夜はオフィシャルパーティ等で出会い、多くの気づきを得ることができる良い機会だと考えてます。何より多くのRubyistとともに過ごす時間が楽しいですよね。

f:id:s_yuka:20190412161356j:plain
昨年のブース

協賛については、Rubyコミュニティを盛り上げたい。この一大イベントを参加者の皆さんと楽しみたい。というのがあります。そして、Sansan という会社、プロダクトを知ってもらいたいです。

ブースにてみなさんと楽しみながら Sansan を知ってもらえるような企画を準備しました。そんな Sansan のミッションは「出会いからイノベーションを生み出す」です。

ミッション:出会いからイノベーションを生み出す

世の中を変えてきたきっかけは、人と人との「出会い」にあり、多くの出会いの中から世の中を変えるプロダクトやサービスなどが生み出されてきました。RubyKaigiに参加される方には、登壇者の方との出会い、他社のエンジニアの方との出会い、Rubyを支える方々との出会いなど、同じ場に集う多くの「出会い」に期待をして参加されている方もいるかと思います。そして、この場の「出会い」からイノベーションが生み出されるかもしれません。

私たちのサービスは、単なる「名刺のデジタル管理」としてだけではなく、イノベーションにつながる「出会い」を生み出すことができるサービスを目指し、名刺からはじまる「出会い」のあり方を変えていこうと挑戦をしている企業です。

サービスとRuby

サービスとして、法人向けクラウド名刺管理サービス「Sansan」と個人向け名刺アプリ「Eight」の2つがあります。

2つとも名刺を管理するサービスとして生まれました。そして、イノベーションにつながる「出会い」を生み出すサービスとして進化をしようとしています。

RubyはEightと基盤技術の部門であるDSOC( Data Strategy & Operation Center)にて利用されています。RubyKaigiにはEightとDSOCのエンジニアが参加します。情報交換をしましょう。

おわりに

昨年までのRubyKaigiでは、Rubyで開発されているEightのサービスを知ってもらいたくEightとしてスポンサードしていましたが、今回は会社自体を知ってもらいたくSansanとして出展します。Eight、DSOCの開発メンバーがブースにいますので、具体的な技術の話もその場でできます。是非遊びにきてください。

f:id:s_yuka:20190412161601j:plain
今年も Rubykaigi でお会いしましょう!

Ruby on Lambdaで実現する、Eightの大規模画像処理基盤

Eight事業部 Platform Unit / Engineering Manager の 藤井洋太郎(yotaro) です。

私のチームはいわゆる技術基盤を担当するチームで、パフォーマンス改善、アーキテクチャ刷新、セキュリティ対応といった課題と日々向き合っています。

今回の記事では、昨年11月に行われた AWS re:Invent にて発表された「Ruby on Lambda」を活用した、Eightの画像処理バッチ基盤の改善について紹介します。

Eightにおける画像処理

Eightサービス内では名刺画像をはじめ多くの画像を扱っていますが、UX向上のためにそれらの画像に対して様々な処理を行っています。

1つの画像に対してぼかし、サムネイル、フォーマット(jpeg/webp)変換などを行い数十ケースの画像を生成しています。

画像処理は以下の図のように画像追加・更新時にSQSにジョブを追加し、EC2バッチサーバーで稼働する Rails プロセスが非同期でポーリングし実行する構成となっていました。

f:id:yotaro-fujii:20190415033355p:plain

スケーラビリティ/パフォーマンス課題の顕在化

この処理タスクはアクセスが増える昼過ぎにピークを迎えるのですが、Eightのバッチ機構の問題もありスケールアウトするためには運用者の手運用が必要になってしまうという課題があり、対応が後手に回り滞留してしまうことが少なからずありました。

また滞留が発生すると、画像取得APIで同期的な画像処理を行うことになり、レスポンス劣化も発生してしまうという影響がありました。

LambdaがついにRuby対応

過去何度か Lambda などへの移行を試みたものの Ruby を使えないというメンテナンサビリティな点において課題があり踏み切れずにいました。
が、ついに昨年の re:invent2018 で Ruby 対応が発表され、この波に乗らない手はないということでEightのバッチ基盤の Lambda 移行に踏み切ることに!

続きを読む

「クラスはオブジェクトである」に辿り着くまで

始めに

初めまして、DSOC エンジニアの冨田です。

突然ですが、明後日は何の日でしょうか?
そう、明後日は待ちに待った RubyKaigi です!
楽しみですね、実は今まで RubyKaigi に参加したことがなく初参加になるので、個人的には Rubyist として一歩前に進めたような気がしてます。たとえ登壇内容が高度過ぎて理解できなくても、その場に行き刺激を受けてきたいと思います。

Sansanに転職後、 Ruby や Rails を使って開発をすることになったため、日々学びと気づきの連続です。そんな日々を改めて振り返ると Ruby に対する理解が進んだなと感じる瞬間があったように思います。
それは「クラスはオブジェクトである」ことを理解したときです。

ということで、本記事では「クラスはオブジェクトである」ことの内実について解説していきます。世に解説記事は出回っており、すでに理解している人も多いかとは思いますが、改めて整理していきたいと思います。

前提知識

早速本題に行きたいところなのですが、その前に理解しておくべき前提知識について整理します。
それは、そもそも「オブジェクト、クラスとは何なのか」ということです。それに答えるために、オブジェクトの階層構造について説明します。ここで「あるオブジェクトを作った時にその裏側でどのようなことが起きているのか」を把握します。前提知識と書きましたが、この内容が本記事のメインになります。思ったよりも長くなってしまったので、理解している箇所は読み流してもらえればと思います。

説明用として、以下のコードを用意しました。

class Parent
  def p_method
    "#{self} call p_method"
  end
end

class Child < Parent
  def initialize(name)
    @name = name
  end

  def c_method
    "#{self} call c_method"
  end
end

chd = Child.new('taro')


この時、オブジェクトの階層構造はどうなっているのでしょうか?
図で示すと下のようになります。[*1]

f:id:tommy_0:20190410074508p:plain

それでは次に、階層構造を構成する各要素について解説していきます。
他にも説明の仕方はありますが、機能的に整理すると以下のようになるかと思います。

オブジェクト

図のどれが該当するか

全てが該当します。「なぜそう言えるのか」を説明するのが本題になります。この内容については後ほど説明します。

どんな機能を持つか
  • インスタンス変数の保持

オブジェクトごとに専用のインスタンス変数の一覧を持つことで、オブジェクトごとに状態を管理できます。また、インスタンス変数はインスタンスメソッドの中で定義されるため、同じクラスのオブジェクトであってもインスタンスメソッド呼び出し有無によってインスタンス変数が異なることがあります。

  • メソッドの呼び出し

オブジェクトに対して唯一可能な操作であり、クラスで定義されたメソッドを呼び出すことができます。
メソッドを呼び出した時には、まずメソッドの探索が行われます。メソッド自体はオブジェクトに存在しないため、メソッドを呼び出したオブジェクト(レシーバ)の特異クラスから順番に、該当のメソッドを見つけるまで継承階層を登っていきます。そして、メソッドを実行する時には、そのレシーバをカレントオブジェクトとして処理が行われます。例えば、図にある赤線で示されているのは、chd をレシーバとして p_method を呼び出した時の流れになります。

カレントオブジェクト

インタプリタが追跡している実行環境となるオブジェクトを指します。Rubyのコードは常にカレントオブジェクトの内部で実行されます。
カレントオブジェクト は self で取得することができ、メソッド内で取得した場合はそのレシーバ、メソッド外(クラス/モジュール内)で取得した場合はそのクラス/モジュールを返します。先程「インスタンス変数はインスタンスメソッドの中で定義される」と書きましたが、それは言い換えれば「レシーバ内でインスタンス変数を定義する」ということになります。

クラス

図のどれが該当するか

大文字から始まるものが該当します。例えば、Child などです。

どんな機能を持つか
  • インスタンス化

クラスからオブジェクトを生成できます。全てのオブジェクトは何かしらのクラスから生成されます。

  • インスタンスメソッドの定義

オブジェクトから呼び出せるインスタンスメソッドを定義できます。
クラスはオブジェクトの振る舞いを規定する役割があるため、メソッド自体はオブジェクトではなくクラスに存在します。

  • 親クラスの継承

クラスには継承元となる親クラスが存在します。メソッド探索範囲に親クラスも含まれるため、オブジェクトから親クラスのインスタンスメソッドを呼び出すことができます。

カレントクラス

カレントオブジェクトと同様に、インタプリタが追跡している情報です。メソッド定義を行うと、それはカレントクラスのインスタンスメソッドになります。
カレントオブジェクトは self で参照できますが、カレントクラスを参照するキーワードはありません。カレントクラスは、メソッド内ではカレントオブジェクトのクラス、メソッド外(クラス/モジュール内)ではそのクラス/モジュールになります。

特異クラス

図のどれが該当するか

#から始まるものが該当します。例えば、#Child などです。
本題を説明する際に重要な概念となるので、いくつか補足したいと思います。
特異クラスとは、特定のオブジェクトのみに適用されるクラスのことであり、オブジェクトを一つしか持てないため別名シングルトンクラスと呼ばれます。
普段はその存在を意識することはないかもしれませんが、以下のようにその実態を確認できます。

chd.singleton_class
=> #<Class:#<Child:0x00007fb0bba21138>>

class Child
  class << self
    self
  end
end
=> #<Class:Child>
どんな機能を持つか
  • 特異メソッドの定義

特定のオブジェクトからのみ呼び出せる特異メソッドを定義できます。

  • 親クラスの継承

特異クラスには継承元となる親クラスが存在します。特異クラスの適用対象によって親クラスは異なります。オブジェクトの特異クラスの場合はそのオブジェクトのクラス、クラスの特異クラスの場合はそのクラスの親クラスの特異クラスになります。メソッド探索範囲に特異クラスも含まれるため、オブジェクトから特異メソッドを呼び出すことができます。

f:id:tommy_0:20190410075013p:plain

モジュール

図のどれが該当するか

Kernel のみが該当します。
モジュール単体では継承階層の中には存在しないのですが、モジュールが読みこまれる(include 等が実行される)と、インタプリタが指定されたモジュールの無名クラスを作成し継承階層の中に組み込みます。
この無名クラスの存在は superclass では確認できませんが、ancestors で確認できます。

Child.ancestors
=> [Child, Parent, Object, Kernel, BasicObject]
どんな機能を持つか
  • メソッドの取り込み

クラスや他モジュールにメソッドを取り込むことができます。取り込み形式は2種類あり、取り込み元がクラスの場合にはインスタンスメソッド、特異クラスの場合には特異メソッドとして取り込まれます。

  • 名前空間の提供

モジュール定義の中には別モジュールやクラスを定義できます。大文字で始まる参照(クラス名やモジュール名)は定数であり、これら定数はスコープを持つため、ネストすることでスコープ階層を作ることができます。
クラス定義でも同様のことが行えますが、クラスはそれに加えてインスタンス化や継承を行えるので、目的に応じて使い分けその意図を明確にする観点から通常はモジュールを使います。

  • 関数の定義

モジュール単体から呼び出せる関数を定義できます。実態としてはモジュールの特異メソッドになります。


この辺りの内容は、メタプログラミングRubyパーフェクトRuby などの書籍で説明されているので一読することをお勧めします。

*1:厳密には、オブジェクトが作成された時点では特異クラスは存在しない(特異メソッドを定義する/特異クラス式を評価する/特異クラスの存在を確認して初めて特異クラスが作成される)のですがわかりやすさのために図示しています。また、Moduleクラス/Classクラス/特異クラスもまた特異クラスを持つのですがわかりやすさのために省略しています。

続きを読む

【Geek Seek Toolsで買われた、気になるモノ達】第4回「TerraMat (スタンディングデスクマット)」

f:id:hartmann3555:20190411151441j:plain

はじめに

こんにちは。DSOC Data Direction Groupでデータエンジニアをしている、千葉祐大です。

最近は、発表された新AirPodsではなく、前モデルから正当進化したBeatsのPowerbeats Proが気になりすぎている毎日です。

さて、弊社の社内制度であるGeek Seek Tools*1で購入されたガジェットの中から、僕がイケてると感じたものを気の赴くままに紹介していく連載なのですが、今回は過去に僕がGeek Seek Toolsで購入したスタンディングデスク用のマットTerraMatとスタンディングデスクの関係について紹介したいと思います。

腰痛対策とスタンディングデスクへの淡い期待

僕は高校生のときにバレーボールで腰を痛めてから、ずっと腰痛持ちです。年1くらいでぎっくり腰にもなっており、腰の負担をいかに減らすかに、かなり神経を削っていました。

特に仕事中はコーディングや資料作成に夢中になると同じ姿勢になりがちなので、2015年に初代Apple Watchを買ってからは1時間ごとに「立ちましょう」というメンションに従い姿勢を変えたり、ストレッチをしたりするようにしていました。

そんな形でデスクに座ることをベースに腰をいたわり続けていた中、Sansanにジョインして初めてスタンディングデスクと出会いました。

ご存知のとおり、スタンディングデスクは机の高さを自由に変えることのできる机で、通常の座る位置から立ってPCを置いて作業ができる高さまで、任意の高さに変化させることができます。

これは座る生活から脱却できる!と思いすぐに要望を出しました。*2

そして、念願のスタンディングデスクを手に入れ、意気揚々とスタンディング生活をはじめました。

はじめから座るつもりはなかったので、貸与されている椅子をオフィスの端に追いやり、座って仕事をするなどという、前時代的なスタイルとは永遠に決別しようと心に決めて、机に向かいました。

*1:生産性向上に資するガジェット・デバイスその他が購入しやすくなる制度。Geek Seek Toolsの詳しい説明については第1回をご覧ください

*2:一番はじめは通常の机が貸与され、希望に応じてスタンディングデスクに変更できる仕組みでした

続きを読む

Sansanプロダクトが生まれ変わります

SansanでChief Product Officerをやっている大津です。
先月のSansan Innovation Project 2019で発表しましたが、この度、法人向けクラウド名刺管理サービス「Sansan」のコンセプトが新しくなりました。
新しいコンセプトは「Sansan, Where Business Starts - 名刺管理から、ビジネスがはじまる」です。
今月はプロダクトリニューアルも予定しており、名実ともに新しいSansanに生まれ変わることになります。
本日はこの新コンセプトの下、プロダクトリニューアルを通してどのような思いで価値を提供していきたいか、改善していきたいかについて少しお話ししたいと思います。

f:id:s_yuka:20190412135743j:plain

新コンセプトにより「活用」を強化

これまでのコンセプトであった「名刺を企業の資産に変える」においては、企業が名刺やそれを通した人脈を資産としてしっかり管理できるように、という目線でプロダクトを提供してきました。
これまでのSansanで実現していた名刺を資産化するための便利な管理機能・運用機能はもちろん今まで通り強化を続けていくのですが、新コンセプトに変わった事で「資産にした名刺データや人脈をどのように活用していくか」によりフォーカスしたプロダクト作りを意識したいと考えています。
今回打ち出している3つの新ソリューション、

  • AI名刺管理
  • 同僚コラボレーション
  • 顧客データHub

これらも「活用」を強く意識しています。
どんな活用をイメージしたソリューションなのか、一つずつご説明します。

f:id:s_yuka:20190412140132j:plain

続きを読む

Doc2Vecによる文書ベクトル推論の安定化について

はじめまして,Sansan DSOC R&Dグループ インターンの小林といいます。
2月下旬から3月末までの間,主に自然言語処理 (NLP) に関連した研究開発に挑戦させて頂きました。大学でNLPを専攻している訳では無いですが,他の研究員の方やインターンの先輩とのディスカッションなど,とにかく刺激的な日々でした。

本稿はNLPブログということで,近年のNLPでスタンダードとなっている,単語・文書の埋め込み手法に言及します。

  • TL; DR
  • Word2Vec / Doc2Vecについて
  • 文書ベクトルによるニュース文書属性判定を試す
    • タスク:スポーツニュースの内容属性の推定
  • Doc2Vecによる文書ベクトル推論の問題点
  • 精度検証実験
    • 実験実行と結果
      • 実験① 以下サンプルテキストに対する独立した2度の文書ベクトル推論(infer_vector()の実行) ×100試行
      • 実験② 複数の文書に対する独立した2度の文書ベクトル推論(infer_vector()の実行) ×100試行でのcos類似度平均と分散の測定
  • 考察・まとめ
  • おわりに

TL; DR

  • Doc2Vecはお手軽に便利に使える
  • 学習済み単語埋め込みを用いたラベル推論をしてみた
  • 文書ベクトルを算出するDoc2Vec.infer_vector()の機能の精度と安定性についての実験と考察をしてみた
  • Doc2Vec.infer_vector()を呼ぶ際は,推論した文書ベクトルのばらつきを減らすために短い文書ほどパラメータepochsを大きめにした方が良さそう

Word2Vec / Doc2Vecについて

Word2Vec とはその名の通り Word-to-Vector を実現する分散表現(単語埋め込み)手法であり,以下のような単語同士の加減算が可能であるとして,5年程前に一躍有名になったとのこと。

マドリード − スペイン + フランス = パリ *1

各単語のベクトル表現により,内積計算で単語間の類似度を数値化することが出来るため,非常に便利です。

参考:コサイン類似度について
参考:Word2Vec のニューラルネットワーク学習過程を理解する

Doc2Vec は,Word2Vecでの単語のベクトル化手法(CBoW, Skip-Gram)をベースに,単語の羅列である文書もベクトルにしてしまおうというもので,多数の文書の中から,文書IDを入力値に,その文書内からランダムに選択された単語を予測することで文書全体の意味を獲得する手法(DBoW : Distributed Bag of Words)と,文脈窓の単語と文書IDを結合したものから中心の単語を予測することで文書の文脈情報を取得する手法があります。(PV-DM : Paragraph Vector - Distributed Memory) 一般的に後者の方が表現の精度が良いですが,前者の方が省メモリであるとされています。
参考:Distributed Representations of Sentences and Documents
参考:Paragraph Vector DBOWの憂鬱

f:id:atsu_jg43yr:20190329144217p:plain
DBoWの模式図:論文より引用

最近は単一モデルで各種タスクのSoTAを達成したBERT *2,ELMo *3のようなAttention / Transformerベースのモデルが主流となりつつあり,NLPをやっている方は発表から5年も経っているWord2Vec, Doc2Vecに対してレガシー感を覚えるかも知れません。

しかし,Doc2Vecは,

  1. gensimによる実装で早い・使いやすい・学習させやすい
  2. DBoWなどは省メモリ*4である
  3. 技術ブログなど,日本語での文献やエントリが非常に豊富 *5

という点を考慮すると,まだまだ便利に使えるものなのではないでしょうか。特に,Doc2Vecの利点はその実装から簡単に得られるParagraph Vector (文書ベクトル) によって単語と可変長の文書を同次元のベクトル表現にし,同列に扱えることと,モデル利用が簡単であることが利点だと考えます。

Doc2Vecによる文書ベクトルと単語ベクトルを同じ空間で扱い内積計算 (類似度算出) することで,例えば『Webからスクレイピングした大量のテキストデータの中から任意のトピックを含むデータのみを抽出したい』というような,特定の文書に対して教師データ無しで任意のラベルセットの中から一つに分類したい状況に応用できます。

*1:Distributed Representations of Words and Phrases and their Compositionality

*2:arXiv:BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding

*3:arXiv:Deep contextualized word representations

*4:論文Distributed Representations of Sentences and Documentsで言及がある

*5:例えば,Qiitaの記事タグ数ではWord2Vecがニューラル言語モデルの中では圧倒的に多い。各件数は,word2vec : 163 / doc2vec :35 / fastText : 38 / ELMO : 27 / BERT : 17 となっている

続きを読む

© Sansan, Inc.