Elasticsearchネストタイプnested

19410 ワード

1.背景紹介
        Elasticsearchを検索エンジンとして使用すると、domainにまたがって検索するシーンに遭遇する可能性があります.例えば、学生のカリキュラム管理システムを作ったり、学生の名前を探したりして、その学生の選択状況を知っているようです.
        もちろん問題を解決する方法はたくさんあります.私は学生を探して、dbに行って学生関連の選択科目を探して、すべての課程を調べることができます.時にはデータ量が大きくなく、私のインデックスが1つの課程次元しかない場合、ネストタイプを使ってこのような問題を解決する必要があります.本文はesとkibinaを使用してインスタンスを操作する.中国語のインスタンスに基づいてik分詞器も使用されているため、具体的には以下の参照ができる.
Elasticsearchのインストールと使用
ElasticsearchでのIK分詞器の使用
2.オブジェクトタイプ
        Elasticsearchはオブジェクトタイプのストレージをサポートし、あるdocumentのフィールドにオブジェクト配列を格納することができます.例えば、カリキュラムをdocumentとして使用すると、このカリキュラムはstudentsフィールドを確立し、そのカリキュラムの下の学生object配列を格納することができます.
       Elasticsearchで、次のようなclassを新規作成します.testインデックス.studentがobject配列タイプである.
PUT /class_test
{
  "mappings":{
	"class_test": {
		"properties": {
			"id": {
				"type": "keyword"
			},
			"name": {
				"analyzer": "ik_max_word",
				"type": "text"
			},
			"type":{
			  "type":"keyword"
			},
			"student":{
			    "properties": {
			       "name":{
			         "analyzer": "ik_max_word",
				        "type": "text"
			       },
			       "id":{
			         "type":"keyword"
			       }
			   }
		  }
      }
	  }
  },
  "settings":{
            "index": {
                "refresh_interval": "1s",
                "number_of_shards": 5,
                "max_result_window": "10000000",
                "mapper": {
                    "dynamic": "false"
                },
                "number_of_replicas": 0
            }
  }
}

        classへtestはデータを入れて、今インデックスの中に全部で2つのデータがあります
{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 2,
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "class_test",
        "_type" : "class_test",
        "_id" : "ijfJ5GoBJeNZPNCWykLR",
        "_score" : 1.0,
        "_source" : {
          "id" : "1",
          "name" : "   ",
          "student" : [
            {
              "id" : "1",
              "name" : "  "
            },
            {
              "id" : "2",
              "name" : "  "
            }
          ]
        }
      },
      {
        "_index" : "class_test",
        "_type" : "class_test",
        "_id" : "Q9NxGGsBa-TqHCWqAaM4",
        "_score" : 1.0,
        "_source" : {
          "id" : "2",
          "name" : "  ",
          "student" : [
            {
              "id" : "3",
              "name" : "  "
            },
            {
              "id" : "4",
              "name" : "  "
            }
          ]
        }
      }
    ]
  }
}

        次に、クエリー文を使用してインデックスをクエリーできます.idが1の学生が参照する授業を検索すると、数学の授業を調べることができます.
GET /class_test/class_test/_search
{
"query": {
  "bool": {
    "must": [
      {
        "match": {
          "student.id": "1"
        }
      }
    ]
  }
}
}
{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 0.2876821,
    "hits" : [
      {
        "_index" : "class_test",
        "_type" : "class_test",
        "_id" : "ijfJ5GoBJeNZPNCWykLR",
        "_score" : 0.2876821,
        "_source" : {
          "id" : "1",
          "name" : "   ",
          "student" : [
            {
              "id" : "1",
              "name" : "  "
            },
            {
              "id" : "2",
              "name" : "  "
            }
          ]
        }
      }
    ]
  }
}

    張三という名前の学生が参加した授業を調べると、数学の授業も調べることができます.
GET /class_test/class_test/_search
{
"query": {
  "bool": {
    "must": [
      {
        "match": {
          "student.name": "  "
        }
      }
    ]
  }
}
}
{
  "took" : 4,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 0.5753642,
    "hits" : [
      {
        "_index" : "class_test",
        "_type" : "class_test",
        "_id" : "ijfJ5GoBJeNZPNCWykLR",
        "_score" : 0.5753642,
        "_source" : {
          "id" : "1",
          "name" : "   ",
          "student" : [
            {
              "id" : "1",
              "name" : "  "
            },
            {
              "id" : "2",
              "name" : "  "
            }
          ]
        }
      }
    ]
  }
}

        しかし、idが1で、李四という名前の学生が参加した授業を調べると
GET /class_test/class_test/_search
{
"query": {
  "bool": {
    "must": [
      {
        "match": {
          "student.name": "  "
        }
      },
      {
        "match": {
          "student.id": "1"
        }
        }
    ]
  }
}
}
{
  "took" : 6,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 0.8630463,
    "hits" : [
      {
        "_index" : "class_test",
        "_type" : "class_test",
        "_id" : "ijfJ5GoBJeNZPNCWykLR",
        "_score" : 0.8630463,
        "_source" : {
          "id" : "1",
          "name" : "   ",
          "student" : [
            {
              "id" : "1",
              "name" : "  "
            },
            {
              "id" : "2",
              "name" : "  "
            }
          ]
        }
      }
    ]
  }
}

        私たちは、出た結果も数学の授業であることを発見しました.これは少しおかしいです.idが1で、名前が李四の学生は一人もいないので、このような授業はあるべきではありません.これはどういうことですか.もともとes内部ではobject配列タイプが平らになりますが、簡単に言えば入力した配列です.実際に格納されているタイプは:
"student.id":[1,2],
"student.name":[  ,  ]

        インデックスの作成も、このような平らな論理に基づいています.このとき,Elasticsearch内のネストタイプを用いて問題を解決することができる.
3.Nestedタイプ
        2と同様に、classという名前のテストインデックスを作成する必要があります.studentにはtypeフィールドがあり、「type」:「nested」とは異なります.
PUT /class
{
  "mappings":{
	"class": {
		"properties": {
			"id": {
				"type": "keyword"
			},
			"name": {
				"analyzer": "ik_max_word",
				"type": "text"
			},
			"type":{
			  "type":"keyword"
			},
			"student":{
			  "type":"nested",
			   "properties": {
			       "name":{
			         "analyzer": "ik_max_word",
				        "type": "text"
			       },
			       "id":{
			         "type":"keyword"
			       }
			   }
			  
			}
		}
	  }
  },
  "settings":{
            "index": {
                "refresh_interval": "1s",
                "number_of_shards": 5,
                "max_result_window": "10000000",
                "mapper": {
                    "dynamic": "false"
                },
                "number_of_replicas": 0
            }
  }
}

        同じデータをインポートし、検索idが1で、名前が李四の学生の授業を使用します.このとき、検索結果が空です.
GET /class/class/_search
{
"query": {
  "bool": {
    "must": [
      {
        "nested": {
          "path": "student",
          "query": {
            "bool": {"must": [
              {
                "match": {
              "student.name": "  "
                }
              },
              {
                "match": {
              "student.id": "1"
            }
              }
            ]}
          }
        }
      }
    ]
  }
}
}
{
  "took" : 3,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 0,
    "max_score" : null,
    "hits" : [ ]
  }
}

4.その他の方式
        このdomainにまたがる検索を解決するには、ネストされたタイプに対してElasticsearchのパフォーマンスを非常に消費する他の方法があります.検索フィールドの値を1つのフィールドに平らに保存するか、学生にインデックスを個別に作成してから、学生-クラスマッピングリレーションシップテーブルに行ってクラスを検索することができます.この辺りは後で紹介する機会があります.
転載先:https://juejin.im/post/5cf3cd576fb9a07ec56e6184