こんにちは、バックエンドエンジニアのまるです。
この記事では、Elasticsearchの検索において、matchとmatch_phraseの違いについて解説します。

Elasticsearchとは

Elasticsearchは、オープンソースの分散型検索エンジンです。大量のデータを高速かつ効率的に検索、分析するために利用されます。テキストデータ、数値、地理情報、日付など、あらゆる種類のデータを扱える汎用的な検索エンジンです。

本記事では日本語の全文検索に絞った解説をします。

matchとmatch_phrase

Elasticsearchの検索には、matchとmatch_phraseという2つのクエリがあります。どちらも「フィールド内に指定された単語が含まれること」を条件としたクエリですが、以下のような違いがあります。

matchクエリは、指定した単語がフィールド内のどこにあっても検索することができます。検索ワードは形態素解析され、デフォルトでは単語のOR検索となります。

match_phraseクエリは、指定した単語がフィールド内で連続して出現している場合にのみ、検索することができます。matchと同じように検索ワードは形態素解析されますが、単語が連続している必要があります。

説明だけでは理解しづらいと思うので、サンプルデータを使った例を見てみましょう。

matchクエリ

初めに、日本語の全文検索をしたいので、kuromojiでindexを登録します。

PUT test_index
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "kuromoji"
      }
    }
  }
}

サンプルデータとして以下の3つの例文を登録します。

POST /test_index/_bulk
{ "index": {}}
{ "title": "ログイン機能のテスト仕様書" }
{ "index": {}}
{ "title": "探索的テストの仕様書" }
{ "index": {}}
{ "title": "書を捨てよ町へ出よう" }

登録が終わったら、さっそく「テスト仕様書」というワードでmatch検索してみましょう。

GET /test_index/_search
{
  "query": {
    "match": {
      "title": "テスト仕様書"
    }
  }
}

Responseは以下のようになります。
(Responseは見やすいように一部省略、整形しています。以降同様)

"hits": [
  {
    "title": "ログイン機能のテスト仕様書"
  },
  {
    "title": "探索的テストの仕様書"
  },
  {
    "title": "書を捨てよ町へ出よう"
  }
]

3つ全てヒットしました。上2つはともかく、「書を捨てよ町へ出よう」という文がヒットするのはおかしいように感じられます。これは、検索ワードが形態素解析されてトークンという単位に分割され、トークンのOR検索として処理されているためです。

検索ワードがどのように分割されているのかは_analyzeで見ることができます。

GET /test_index/_analyze
{
    "field": "title",
    "text": "テスト仕様書"
}
{
  "tokens": [
    {
      "token": "テスト",
    },
    {
      "token": "仕様",
    },
    {
      "token": "書",
    }
  ]
}

「テスト仕様書」というワードは、「テスト」と「仕様」と「書」に分割されて検索に使われます。デフォルトではトークンのOR検索となるため、「書」を含む「書を捨てよ町へ出よう」がヒットした、ということです。

分割された単語すべてが含まれてほしい場合は、operatorオプションにANDを指定すればよいです。

GET /test_index/_search
{
  "query": {
    "match": {
      "title": {
        "query": "テスト仕様書",
        "operator": "AND"
      }
    }
  }
}
"hits": [
  {
    "title": "ログイン機能のテスト仕様書"
  },
  {
    "title": "探索的テストの仕様書"
  }
]

「テスト」「仕様」「書」が全て含まれる文だけがヒットしました。

match_phraseクエリ

match_phraseは、指定した単語がフィールド内で連続して出現している場合のみヒットします。

同じサンプルデータを使ってmatch_phrase検索してみましょう。

GET /test_index/_search
{
  "query": {
    "match_phrase": {
      "title": "テスト仕様書"
    }
  }
}
"hits": [
  {
    "title": "ログイン機能のテスト仕様書"
  }
]

「ログイン機能のテスト仕様書」という文だけがヒットしました。これは、match_phraseの場合「テスト」「仕様」「書」がこの順序で連続して出現する文のみがヒットするためです。従って完全一致検索のように使うことができます。

完全一致検索では厳しすぎるのでもう少し柔軟な検索をしたいという場合には、slopというオプションを使うとよいです。slopオプションには「各単語の間にいくつの余計な単語を含んでよいか」を指定することができます。

GET /test_index/_search
{
  "query": {
    "match_phrase": {
      "title": {
        "query": "テスト仕様書",
        "slop": 1
      }
    }
  }
}
"hits": [
  {
    "title": "ログイン機能のテスト仕様書"
  },
  {
    "title": "探索的テストの仕様書"
  }
]

「テスト」と「仕様」の間に1つ余計な単語が含まれていてもヒットすることが確認できます。

終わりに

この記事ではElasticsearchのmatchとmatch_phraseの違いについて解説しました。Elasticsearchは非常に汎用的な検索エンジンですので、他のクエリと組み合わせてもっと詳細で柔軟な検索を実現することもできます。

この記事がみなさんのお役に立てば幸いです。

SHARE

  • facebook
  • twitter

SQRIPTER

AGEST Engineers

AGEST

記事一覧

AGESTのエンジニアが情報発信してます!

株式会社AGEST

Sqriptsはシステム開発における品質(Quality)を中心に、エンジニアが”理解しやすい”Scriptに変換して情報発信するメディアです

  • 新規登録/ログイン
  • 株式会社AGEST