こんにちは。@Ssk1029Takashiです。
最近は家でもどうにかラーメンを食べられないかと試行錯誤しています。
タグ検索とは、キーワード検索とは違い、検索する前からユーザーが選択肢からキーワードをセレクトボックスなどで選んで、検索できる検索方法です。
通常のキーワード検索と違って、ユーザーが0からキーワードを考える必要がないため、効率的に情報を絞り込めます。
もしくは、キーワード検索と併用して使用することも可能です。
ただ、コンテンツごとにタグを設定するのはとても手間がかかります。
コンテンツ作成者も必ずしもタグを設定してくれるとは限りません。
このような時に、自動でタグ付けをしてくれる仕組みがあると楽にタグ検索を実現できます。
ただ、単純な形態素解析で名詞をタグとすると、ゴミが多くなってしまいます。
そこで、今回は、日本語処理ライブラリであるGiNZAの固有表現抽出機能とElasticsearchを使って、簡易的にタグ検索を実現してみます。
今回のゴール
タグ検索というと、以下の画面のようにタグをチェックボックスで選択して、選択したタグによって検索結果が変わる画面が一般的です。
今回目指すのは上記の検索のデータ投入・検索クエリを作成していきます。
今回書かないこと
本記事は以下のことは対象外としています。
1. 検索画面の実装
2. Elasticsearchの基本的なクエリの使い方
固有表現抽出とは
固有表現抽出とは、自然言語処理技術のうちの一つで、文章中から人名・組織名・地名などの固有名詞や、「100%」などの数値表現を抽出する技術です。
一般的には、以下の8つのクラスが固有表現のクラスとして抽出されます。
ART 固有物名、LOC(地名)、ORG(組織)、PSN(人名)、DAT(日付)TIM(時間)、MNY(金額)、PNT(割合)
どういうときに使われるかというと、例えば、未知語を辞書登録するために固有名詞を抽出したり、人名・企業名を抽出してプライバシー保護に使用したりなどが考えられます。
GiNZAの場合、より細かいクラスを定義しています。
拡張固有表現階層 定義
GiNZAはGSK2014-A (2019) BCCWJ版という、上記の固有表現クラスを定義したコーパスで学習されたモデルをもとに固有表現抽出を行います。
非常に細かく固有表現を分類しているので、より詳細な分析ができるようになっています。
今回は、文章中の固有表現はその文章の中心的な話題を示すことが多いのではないか仮定して、タグ検索に応用してみます。
どうやって解決するか
以下に概略図を書きました。
つまり、本文とは別に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)
結果
このように、文章のどの単語が固有表現として抽出されたのかを一目で確認できます。
検索に応用する
それでは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 BotとAWSの画像分析サービスを使って社員のワーク&ライフハックを行った内容を紹介したいと思います。
""",
"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のタグクラウドで見てみると以下のようになります。
最近記事が多かった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を使ったタグ検索は実現できます。
画面にすると以下のようになります。
0からキーワードを考えるよりも、なんとなくでも文書の内容がわかったほうが探しやすいですね。