Follow US
facebook twitter
NO. 221
TECH BLOG
じげんのテック

求人サイトの「在庫」を自動で管理しようとした

12.19.2022
  • 本記事の内容
  • 求人サイトにおける「在庫」の難しさ
  • ブランド名を抜き出すために..
    • ①特許DBからマスタを作る(▲)
    • ②手動でマスタを作る(▲)
    • ③LCSによる共通部分の抜き出し(▲)
    • ④類似度をとって共通部分を抜き出す(◯)
  • 運用の経過と今後の展望
  • おわりに

本記事の内容

「在庫」と聞いてどんなものを思い浮かべるでしょうか?
おそらく、飲食店における食材や、アパレル店舗における衣服を想像するのではないでしょうか。
「在庫を持たないビジネスモデル」などとググってみると、真っ先にネットビジネスがヒットしますが、ネットビジネスにおいても在庫の概念が存在します。

我々が運営する求人サイトでは、在庫として約200万件のお仕事案件情報を保有しており、
その管理においては、ユーザがよりお仕事を探しやすくする案件整理(=検索最適化)が重要になります。
そこで我々は、検索最適化のための在庫管理施策として
「ブランド名による案件のセグメント分け」を自動で行うシステムの開発を行いました。
最終的には類似度計算による方法を採用しましたが、本記事ではその方法に至るプロセスと具体的な方法、その後について、サンプルコードと合わせてご紹介します。

求人サイトにおける「在庫」の難しさ

我々が運営する求人サイト「アルバイトEX」(https://arubaito-ex.jp/)では、自社で用意したものだけではなく、他企業と提携し、複数のポータルサイトから情報を取り込んでいます。

そのため、「情報の型」が企業ごとにバラバラです。

タイトルの入れ方、会社の記載方法やアピールポイントが異なってきます。

求人案件をユーザが見分ける際に以下の3つが想定されますが、

・求人タイトル

・募集会社名

・ブランド名

我々が保有しているデータはカラムとして、求人タイトルと募集会社名は持っていますが、ブランド名に関しては持っていません。

このブランド名とは、飲食店でいえば「すき家」「大戸屋」「サイゼリヤ」アパレルで言えば「ユニクロ」「GU」「ZARA」のようなものを指します。

求人サイトを見てみるとこのようなブランド名はタイトルの一部に含まれていたり、募集会社名の”株式会社”を除いたものだったり、略語であったりとそのパターンは様々です。

このブランド名が案件に結びついていないと、ネット上で広告を出稿する際に対象とするキーワードが不正確になってしまいます。

(在庫を持っていないのに広告が出稿されて広告費が無駄になる、在庫をたくさん持っているのに広告費がかけられていない、といった状況になります。)

以前の状態では、このキーワードを目検で抜き出したり、SQL文でDBから抜き出す際に前方後方文字除外や記号の除外などをレガシーに行っていましたが、あまりにも工数がかかっていました。

そこで我々は、頂いている案件の文字列からなんとかブランド名を抜き出すことができないかと考え、次のような方法を試していきました。

ブランド名を抜き出すために..

・①特許DBからマスタを作る(▲)

まず初めに考えたのは、ブランド名が蓄積されたデータベース(以下DB)が存在すれば、その内容と照合することでブランド名に対する在庫を明らかにできるということです。

「ブランド名」=「特許」と考えた私たちは特許庁のDBを用いてこのブランド名を抜き出すことを考え、調査を行いました。

結果としては、抽出精度の担保とDBの確保の点から難しいという結論に至りました。

まず、我々が保有している案件から抜き出したいブランド名をいくつかサンプルとして抜き出し、そのブランド名が特許庁のHPに登録しているかを調べますと、これはしっかりと登録されていました。しかし、案件のタイトルや文面の他の文言も特許として登録されてしまっていたため、DBとの照合だけでは不必要な情報も合わせて抜き出されてしまうため、抽出精度の点において不十分であると判断しました。

また、特許庁のDBはAPIなどで外部に公開しているわけではないため、DBの確保という点でも難易度が高く、こちらの案に関しては見送りとしました。

・②手動でマスタを作る(▲)

次に我々が考えたのは、前述の特許DB案にて表出したDBとの照合だけでは抽出精度が担保できないため、DB自体も不必要なものを除いた形で整備しなくてはならない点についての深掘りでした。

そこで発見したことは、ブランドを抜き出すためのルール(どのようなものをブランド名として定義するか、複数存在した場合はどうするか)が構造化されていなかったことです。

業務自動化という観点で考えれば、「人手でやっていた作業を構造化し、システムに落とし込む」ことになりますので、まずは業務を構造化できるよう人手の作業をはさみ、その後自動化していくプロセスに変更することで徐々に臨む形を作っていけると考えました。

具体的には、目検で抜き出したブランドに関してマスタ化し、資産として蓄積していき、そのマスタとの照合によってブランド名を抜き出す方法です。

この方法を検証してみた結果、更新性が追いつかないという点で棄却されました。

仕事を表すキーワードやユーザの興味関心に対するトレンドは日々絶えず変化しており、一度マスタを作ったとして、完全網羅できるはずもなく、トレンドに追いつくことも人手では難しいことがわかりました。

業務設計としてヒューリスティックに網羅性とトレンド性を追いかけていくものになりますが、人手では到底追いつかないため、構造化に関しても工数がかかりすぎ、見送りとなりました。

・③LCSによる共通部分の抜き出し(▲)

改めて手動による解決から自動による解決を考え出した我々ですが、

②を行っていく中で、得られた知見として、抜き出したいブランド名は多くの場合、求人タイトルに”同じ文字列”で含まれていることがわかりました。

そこで求人タイトルの全文に対して、LCS(Longest Common Sequence)というアルゴリズムを用いて3文字以上の共通部分の抜き出しを行い、閾値を超える件数の結果を返した文字列をブランド名として扱う方法を検証しました。

この結果としては、3文字以上という定義の部分が難しく、先の例で言えば「GU」のような2文字の場合もあれば、「交通費支給」のような3文字以上の共通部分が抜き出されてしまう場合が多発し、我々のテストケースで検証した結果は、ブランド名の一致率は10%を下回る結果となりました。

また、3文字以上で指定した場合、ある程度件数のある案件は「すき家」だけでなく「すき家 東京」と余計な部分まで取れてしまうパターンが多く、共通部分が取れすぎてしまい、その精度を指定文字数の調整だけでは行えないという結論に至りました。

・④類似度をとって共通部分を抜き出す(◯)

③における失敗の要因として、全てのブランド名を網羅的に抜き出す完璧なアルゴリズムを追い求めてしまったことを考えた我々は、②で行ったようなヒューリスティックな方法をアルゴリズムで実装する方針を考えました。

つまり、一致率100%を目指すのではなく、少なくとも一致件数が多いブランド名に関しては抜き出すことの出来るシステムを構築し、出口の工程で目検を挟むことで結果的に業務効率化を図る方針を立てました。

ここで我々が着目したのが類似度という観点です。

共通部分の抜き出しでは、完全一致で取っていましたが、この部分に調整可能な変数を挟むことで全体として抜き出されるブランド名の長さを調整しようとしました。

具体的には、保有しているデータをsortし、隣り合ったデータのタイトルの文字列を比較し、一定以上の類似度があった場合に共通部分を取得しながらデータを絞り込んでいきます。この際に、比較回数とボーダーとする類似度を調整することでテストケースに対する一致率を高めていきました。結果的には、一致率70~80%の結果を出すことができました。

この要因としては、自分達の想定以上に同じ型でブランド名が含まれていることが多く、

精度の高い結果となる類似度と比較回数が一定の値に収束できたことがあります。
以下に比較回数2類似度0.4のサンプルコードを示すのでご参考ください。

#ライブラリのimport
import pandas as pd
from difflib import SequenceMatcher

### df[title]に求人のタイトルが入っているとする

#比較文字列列(_title_)を追加
#隣同士のデータを比較する
comp_str_arr = df['title'].copy()
comp_str_arr = comp_str_arr.shift(-1)
df['_title_'] = comp_str_arr
df = df.drop(df.index[-1],axis=0)

#類似度で分類
def create_similarity_class(row):
    r = SequenceMatcher(None, str(row['title']), str(row['_title_'])).ratio()
    if r > 0.40:
        return True
    else:
        return False
df['Similarity'] = df.apply(create_similarity_class,axis=1)

#SimilarityがTrueのもののみdf2に抽出
df2 = df.copy()
df2 = df2[df2.Similarity == True]

運用の経過と今後の展望

現在はこのシステムをAPI化することにより、現状保有している案件データからおおよそのブランド名を吐き出すことが出来るようになりました。

このシステムにより、広告出稿の際のキーワード選定にかかる多量の工数を削減することができ、よりユーザが求めるキーワードで案件を検索結果に表示することが出来るようになりました。

しかし依然として目検による工数は発生しており、抜き出したブランド名に関しても重複部分が存在するため、未だ改善の余地はあると考えています。

現状ではこの改良として、最新辞書の形態素解析による抜き出したブランド名のさらなる判定、地名や記号の除外といったフィルタを用いています。

また、②で実施しようとしたマスタ化の途中成果も改良に活きており、除外kwマスタを間に噛ませることで80~90%ほどの一致率まで高めることができました。

今後の展望としては、機械学習によるブランド名の抜き出しが考えられ、類似度によってある程度抜き出したブランド名に対し正誤をつけていくことでさらなる人手の削減が期待できます。

また、類似度に関しても現状では外部のライブラリを用いているため、こちらも内製で学習させていくことでより求人サイトに特化し、我々の資産となるようなシステムに拡張していけると考えています。

プロジェクトの進め方としても、このようにまとめてみると、一つひとつの検証が次の検証の資産となっており、我々として良いチャレンジになっていることを感じます。

一方で、課題感に対する幅を持たせぬまま進んだことにより自動/手動を行ったり来たりしてしまった面も反省点としてあげられます。

我々としてもこの反省を活かし網羅的にPDCAを回し、ユーザやクライアントの皆様により良い検索体験をお届けできるよう精進してまいりたいと思います。

おわりに

本記事では、
求人サイトにおける「在庫」管理の扱いの難しさであるブランド名の抜き出しを解決するため、方法を模索した軌跡と、最終的に採用した類似度計算を用いた方法とその運用経過、展望をまとめました。

自分が前回書かせていただいた記事がありますので、興味あれば覗いてみてください。

リンク


SHARE
  • facebook
  • twitter
Top