ElasticSearchによる全文検索の概要

ElasticSearchによる全文検索のクイックイントロ

1. 概要

全文検索クエリおよびドキュメントに対する言語検索を実行します。 単一または複数の単語またはフレーズが含まれ、検索条件に一致するドキュメントを返します。

ElasticSearchは、無料のオープンソース情報検索ソフトウェアライブラリであるApache Luceneに基づく検索エンジンです。 HTTP WebインターフェースとスキーマフリーのJSONドキュメントを備えた分散型フルテキスト検索エンジンを提供します。

この記事では、ElasticSearch REST APIを検証し、HTTPリクエストのみを使用した基本操作を示します。

2. セットアップ

マシンにElasticSearchをインストールするには、official setup guideを参照してください。

RESTfull APIはポート9200で実行されます。 次のcurlコマンドを使用して、正常に実行されているかどうかをテストします。

curl -XGET 'http://localhost:9200/'

次の応答を確認すると、インスタンスは適切に実行されています。

{
  "name": "NaIlQWU",
  "cluster_name": "elasticsearch",
  "cluster_uuid": "enkBkWqqQrS0vp_NXmjQMQ",
  "version": {
    "number": "5.1.2",
    "build_hash": "c8c4c16",
    "build_date": "2017-01-11T20:18:39.146Z",
    "build_snapshot": false,
    "lucene_version": "6.3.0"
  },
  "tagline": "You Know, for Search"
}

3. ドキュメントのインデックス作成

ElasticSearchはドキュメント指向です。 文書を保存および索引付けします。 インデックス作成は、ドキュメントを作成または更新します。 インデックス作成後、列データの行ではなく、完全なドキュメントを検索、並べ替え、およびフィルター処理できます。 これは、データについて根本的に異なる考え方であり、ElasticSearchが複雑な全文検索を実行できる理由の1つです。

ドキュメントはJSONオブジェクトとして表されます。 JSONシリアル化は、ほとんどのプログラミング言語でサポートされており、NoSQL運動で使用される標準形式になっています。 シンプルで簡潔で読みやすいです。

次のランダムエントリを使用して、全文検索を実行します。

{
  "title": "He went",
  "random_text": "He went such dare good fact. The small own seven saved man age."
}

{
  "title": "He oppose",
  "random_text":
    "He oppose at thrown desire of no. \
      Announcing impression unaffected day his are unreserved indulgence."
}

{
  "title": "Repulsive questions",
  "random_text": "Repulsive questions contented him few extensive supported."
}

{
  "title": "Old education",
  "random_text": "Old education him departure any arranging one prevailed."
}

ドキュメントのインデックスを作成する前に、ドキュメントの保存場所を決定する必要があります。 複数のインデックスを作成して、複数のタイプを含めることができます。 これらのタイプは複数のドキュメントを保持し、各ドキュメントには複数のフィールドがあります。

次のスキームを使用してドキュメントを保存します。

text:インデックス名。 article:タイプ名。 id:この特定の例のテキスト入力のID。

ドキュメントを追加するには、次のコマンドを実行します。

curl -XPUT 'localhost:9200/text/article/1?pretty'
  -H 'Content-Type: application/json' -d '
{
  "title": "He went",
  "random_text":
    "He went such dare good fact. The small own seven saved man age."
}'

ここではid=1を使用していますが、同じコマンドとインクリメントされたIDを使用して他のエントリを追加できます。

4. ドキュメントを取得する

すべてのドキュメントを追加したら、次のコマンドを使用して、クラスター内にあるドキュメントの数を確認できます。

curl -XGET 'http://localhost:9200/_count?pretty' -d '
{
  "query": {
    "match_all": {}
  }
}'

また、次のコマンドでidを使用してドキュメントを取得できます。

curl -XGET 'localhost:9200/text/article/1?pretty'

そして、弾性検索から次の答えを得る必要があります。

{
  "_index": "text",
  "_type": "article",
  "_id": "1",
  "_version": 1,
  "found": true,
  "_source": {
    "title": "He went",
    "random_text":
      "He went such dare good fact. The small own seven saved man age."
  }
}

ご覧のとおり、この回答はid 1を使用して追加されたエントリに対応しています。

5. ドキュメントのクエリ

では、次のコマンドを使用して全文検索を実行しましょう。

curl -XGET 'localhost:9200/text/article/_search?pretty'
  -H 'Content-Type: application/json' -d '
{
  "query": {
    "match": {
      "random_text": "him departure"
    }
  }
}'

そして、次の結果が得られます。

{
  "took": 32,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 2,
    "max_score": 1.4513469,
    "hits": [
      {
        "_index": "text",
        "_type": "article",
        "_id": "4",
        "_score": 1.4513469,
        "_source": {
          "title": "Old education",
          "random_text": "Old education him departure any arranging one prevailed."
        }
      },
      {
        "_index": "text",
        "_type": "article",
        "_id": "3",
        "_score": 0.28582606,
        "_source": {
          "title": "Repulsive questions",
          "random_text": "Repulsive questions contented him few extensive supported."
        }
      }
    ]
  }
}

ご覧のとおり、“him departure”を探しており、スコアが異なる2つの結果が得られます。 最初の結果は明らかです。テキスト内に検索が実行されており、ご覧のとおり、スコアは1.4513469です。

ターゲットドキュメントに「彼」という単語が含まれているため、2番目の結果が取得されます。

デフォルトでは、ElasticSearchは関連性スコア、つまり各ドキュメントがクエリにどれだけ一致するかで一致結果をソートします。 2番目の結果のスコアは最初のヒットに比べて小さいため、関連性が低いことに注意してください。

ファジーマッチングは、「ファジー」に似ている2つの単語を同じ単語であるかのように扱います。 最初に、あいまいさの意味を定義する必要があります。

Elasticsearchは、ファジーネスパラメーターで指定された2の最大編集距離をサポートします。 あいまいさパラメータをAUTOに設定すると、次の最大編集距離が得られます。

  • 1文字または2文字の文字列の場合は0

  • 3、4、または5文字の文字列の場合は1

  • 5文字を超える文字列の場合は2

編集距離が2の場合、関連していないように見える結果が返されることがあります。

最大のあいまいさ1で、より良い結果とより良いパフォーマンスを得ることができます。 距離とは、2つのシーケンス間の差を測定するための文字列メトリックであるレーベンシュタイン距離を指します。 非公式には、2つの単語間のLevenshtein distanceは、1文字の編集の最小数です。

わかりました。あいまいな状態で検索を実行しましょう。

curl -XGET 'localhost:9200/text/article/_search?pretty' -H 'Content-Type: application/json' -d'
{
  "query":
  {
    "match":
    {
      "random_text":
      {
        "query": "him departure",
        "fuzziness": "2"
      }
    }
  }
}'

結果は次のとおりです。

{
  "took": 88,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 4,
    "max_score": 1.5834423,
    "hits": [
      {
        "_index": "text",
        "_type": "article",
        "_id": "4",
        "_score": 1.4513469,
        "_source": {
          "title": "Old education",
          "random_text": "Old education him departure any arranging one prevailed."
        }
      },
      {
        "_index": "text",
        "_type": "article",
        "_id": "2",
        "_score": 0.41093433,
        "_source": {
          "title": "He oppose",
          "random_text":
            "He oppose at thrown desire of no.
              \ Announcing impression unaffected day his are unreserved indulgence."
        }
      },
      {
        "_index": "text",
        "_type": "article",
        "_id": "3",
        "_score": 0.2876821,
        "_source": {
          "title": "Repulsive questions",
          "random_text": "Repulsive questions contented him few extensive supported."
        }
      },
      {
        "_index": "text",
        "_type": "article",
        "_id": "1",
        "_score": 0.0,
        "_source": {
          "title": "He went",
          "random_text": "He went such dare good fact. The small own seven saved man age."
        }
      }
    ]
  }
}'

ファジーがわかるように、より多くの結果が得られます。

あいまいさは、無関係に見える結果を取得する傾向があるため、慎重に使用する必要があります。

7. 結論

このクイックチュートリアルでは、indexing documents and querying Elasticsearch for full-text search, directly via it’s REST APIに焦点を当てました。

もちろん、必要なときに複数のプログラミング言語で使用できるAPIを用意していますが、APIは依然として非常に便利であり、言語に依存しません。