Taste of Tech Topics

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

GiNZAの固有表現抽出とElasticsearchを使って自動でタグ検索

こんにちは。@Ssk1029Takashiです。
最近は家でもどうにかラーメンを食べられないかと試行錯誤しています。

タグ検索とは、キーワード検索とは違い、検索する前からユーザーが選択肢からキーワードをセレクトボックスなどで選んで、検索できる検索方法です。
通常のキーワード検索と違って、ユーザーが0からキーワードを考える必要がないため、効率的に情報を絞り込めます。
もしくは、キーワード検索と併用して使用することも可能です。

ただ、コンテンツごとにタグを設定するのはとても手間がかかります。
コンテンツ作成者も必ずしもタグを設定してくれるとは限りません。
このような時に、自動でタグ付けをしてくれる仕組みがあると楽にタグ検索を実現できます。

ただ、単純な形態素解析で名詞をタグとすると、ゴミが多くなってしまいます。
そこで、今回は、日本語処理ライブラリであるGiNZAの固有表現抽出機能とElasticsearchを使って、簡易的にタグ検索を実現してみます。

今回のゴール

タグ検索というと、以下の画面のようにタグをチェックボックスで選択して、選択したタグによって検索結果が変わる画面が一般的です。
f:id:acro-engineer:20200426155821p:plain

今回目指すのは上記の検索のデータ投入・検索クエリを作成していきます。

今回書かないこと

本記事は以下のことは対象外としています。
1. 検索画面の実装
2. Elasticsearchの基本的なクエリの使い方

GiNZAとは

GiNZAについては、過去にブログで紹介しているので、詳細はそちらを参照してください。
acro-engineer.hatenablog.com

今回はこのGiNZAの固有表現抽出をタグ付けに使用していきます。

固有表現抽出とは

固有表現抽出とは、自然言語処理技術のうちの一つで、文章中から人名・組織名・地名などの固有名詞や、「100%」などの数値表現を抽出する技術です。
一般的には、以下の8つのクラスが固有表現のクラスとして抽出されます。
ART 固有物名、LOC(地名)、ORG(組織)、PSN(人名)、DAT(日付)TIM(時間)、MNY(金額)、PNT(割合)

どういうときに使われるかというと、例えば、未知語を辞書登録するために固有名詞を抽出したり、人名・企業名を抽出してプライバシー保護に使用したりなどが考えられます。

GiNZAの場合、より細かいクラスを定義しています。
拡張固有表現階層 定義
GiNZAはGSK2014-A (2019) BCCWJ版という、上記の固有表現クラスを定義したコーパスで学習されたモデルをもとに固有表現抽出を行います。

非常に細かく固有表現を分類しているので、より詳細な分析ができるようになっています。

今回は、文章中の固有表現はその文章の中心的な話題を示すことが多いのではないか仮定して、タグ検索に応用してみます。

どうやって解決するか

以下に概略図を書きました。
f:id:acro-engineer:20200425084125p:plain

つまり、本文とは別にGiNZAで固有表現として抽出したキーワードをタグとしてElasticsearchに投入します。
検索時はタグとして投入したキーワードの一覧を取得します。

GiNZAでの固有表現抽出

まず、GiNZAで固有表現抽出を試してみましょう。

実際に動かすコードは以下のようになります。

import spacy

nlp = spacy.load('ja_ginza')
doc = nlp("Acroquestは新横浜にある会社です。")

for ent in doc.ents:
    print(ent.text, ent.start_char, ent.end_char, ent.label_)

出力結果

Acroquest 0 9 Company
新横浜 10 13 City

ちゃんと「Acroquest」を会社、「新横浜」を地名と認識しています。

また、Spacyには固有表現抽出された結果をより分かりやすく可視化する機能もあります。

from spacy import displacy

displacy.render(doc, style="ent", jupyter=True)

結果
f:id:acro-engineer:20200419171932p:plain

このように、文章のどの単語が固有表現として抽出されたのかを一目で確認できます。

検索に応用する

それではElasticsearchと固有表現抽出を使ったタグ検索を実現していきます。

検索データを作る

コードにすると以下のようになります。

nlp = spacy.load('ja_ginza')
es_client = Elasticsearch()

for title, sentence in zip(titles, sentences):
  doc = nlp(sentence)
  tags = [ent.text.lower() for ent in doc.ents]
  tags = list(set(tags)) #重複するタグを削除
  document = {
      "title": title,
      "sentence": sentence,
      "tag": tags
  }
  es_client.index(index="content", doc_type="_doc", body=document)

各フィールドの値は以下のようにします。

フィールド 説明
title 記事のタイトル(画面表示用に投入)
sentence 記事本文
tag 記事から固有表現抽出で作成したタグ

試しに、このブログのここ最近の冒頭文とタイトルを入れてみました。
Elasticsearchに投入後は、以下のようにデータが登録されます。
(抜粋)

{
    "title": "LINE BotとAmazon Rekognitionでワーク&ライフハック",
    "sentence": """
こんにちは、DevOpsエンジニアの横山です。
今回は、LINE BotAWSの画像分析サービスを使って社員のワーク&ライフハックを行った内容を紹介したいと思います。
             """,
          "tag": [
        "line bot",
        "社員",
        "aws",
        "横山",
        "devopsエンジニア"
    ]
},
{
    "title" : "ANGEL Dojo最終発表で「アライアンス賞」を受賞しました!",
    "sentence" : """
こんにちは!
2年目エンジニアの古賀です。
先日ブログで紹介したANGEL Dojoですが、 2020年3月6日、最終発表があり、AWSの審査員の方々が選ぶ「アライアンス賞」を受賞しました!
上位3チームに選ばれると貰える賞の1つで、 今回がんばってきたことが1つの形になって、とても嬉しいです。
アライアンス賞の詳細は後ほど^^
※ANGEL Dojo とは、AWS様主催の疑似プロジェクトを通して、 クラウド開発力とAmazonの文化を学び、ビジネスで日本を元気にしよう! という企画です。
       """,
    "tag" : [
      "2020年3月6日",
      "上位3チーム",
      "angel dojo",
      "aws",
      "2年",
      "古賀",
      "日本",
      "アライアンス賞",
      "amazon",
      "審査員",
      "1つ",
      "目エンジニア"
    ]
  }
},

入ったタグをKibanaのタグクラウドで見てみると以下のようになります。
f:id:acro-engineer:20200425154433p:plain
最近記事が多かったANGEL DojoやAutoGluonなどの単語が拾えていますね。

数値表現や日付が混じってしまっていますが、GiNZAは固有表現で識別したクラスも取得できるので、数値や日付はフィルタするようにすればより精度が高く抽出できます。

検索する

データが入れば、次は検索してみましょう。
タグ検索には以下の2ステップが必要です。
1. タグの一覧取得
2. 選択したタグでの検索

1のタグ一覧の取得はtagフィールドに対して、Terms Aggregationを実行することで取得できます。

GET content/_search
{
  "size": 0,
  "aggs": {
    "terms": {
      "terms": {
        "field": "tag",
        "size": 10
      }
    }
  }
}

上のクエリで、tagをリストを出現数順に取得することができます。

2の選択したタグでの検索は、1で取得したタグから選択した値をtagフィールドにTerms Queryで検索することで取得できます。

GET content/_search
{
  "size": 0,
  "aggs": {
    "terms": {
      "terms": {
        "field": "tag",
        "size": 10
      }
    }
  }
}

以上で、GiNZAを使ったタグ検索は実現できます。

画面にすると以下のようになります。
f:id:acro-engineer:20200426155821p:plain

0からキーワードを考えるよりも、なんとなくでも文書の内容がわかったほうが探しやすいですね。

まとめ

GiNZAの固有表現抽出とElasticsearchを使って自動でタグ検索を実現してみました。
改善点としては、数詞や日付が入ってしまっているので、抽出されたタグから固有表現のクラスでフィルタリングするとより精度の高いタグ検索が可能になります。
GiNZAは3.0から固有表現のクラスがより細かくなっているため、扱いやすくなっています。

それでは、皆さんもよいNLPライフを。

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


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

 
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。
Kaggle Masterと働きたい尖ったエンジニアWanted! - Acroquest Technology株式会社のデータサイエンティストの求人 - Wantedlywww.wantedly.com