es針對nested型別資料無法進行過濾查詢的問題記錄

blayn發表於2023-10-08

問題描述

es中存在有一個名為task_data_1的索引,其欄位對映關係如下所示:
{
    "task_data_1" : {
        "mappings" : {
        "dynamic_templates" : [
            {
                "dates" : {
                "match_mapping_type" : "date",
                    "mapping" : {
                        "type" : "date"
                    }
                }
            },
            {
            "doubles" : {
                "match_mapping_type" : "double",
                "mapping" : {
                    "type" : "double"
                    }
                }
            },
            {
            "objects" : {
                "match_mapping_type" : "object",
                "mapping" : {
                    "type" : "object"
                    }
                }
            },
            {
            "longs" : {
                "match_mapping_type" : "long",
                "mapping" : {
                    "type" : "integer"
                }
                }
            },
            {
            "strings" : {
                "match" : "*",
                "match_mapping_type" : "string",
                "mapping" : {
                    "type" : "keyword"
                }
            }
            }
            ],
            "properties" : {
                "createUsername" : {
                    "type" : "keyword"
                },
                "data" : {
                    "type" : "nested",
                    "dynamic" : "true",
                    "properties" : {
                        "daterange102110" : {
                            "type" : "date"
                        },
                        "input18779" : {
                            "type" : "keyword"
                        },
                        "rate48025" : {
                            "type" : "integer"
                        },
                        "textarea24212" : {
                            "type" : "keyword"
                        },
                        "textarea38172" : {
                            "type" : "keyword"
                        },
                        "timerange47544" : {
                            "type" : "keyword"
                        },
                        "url" : {
                            "type" : "keyword"
                        }
                    }
                },
                "formId" : {
                    "type" : "long",
                    "store" : true
                },
                "updateUsername" : {
                    "type" : "keyword"
                }
            }
        }
    }
}
透過createUsername、updateUsername、formId等欄位可以正常進行過濾查詢功能,但是data這個map中的所有欄位都無法正常進行過濾查詢功能。

解決過程

起初,我是直接用map中對應的欄位名進行過濾查詢,編寫的程式碼生成的DSL如下所示:
POST task_data_1/_search
{
  "from": 0,
  "size": 10,
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "input18779": {
              "value": "3213",
              "boost": 1
            }
          }
        }
      ],
      "adjust_pure_negative": true,
      "boost": 1
    }
  },
  "sort": [
    {
      "createTime": {
        "order": "desc"
      }
    }
  ],
  "track_total_hits": 2147483647
}
這樣子的查詢語法有很明顯的問題,因為input32768這個欄位是巢狀在data這個map中的,直接使用input32768這個欄位名是無法查詢到對應資料的。
 
發現問題後,我修改了程式碼邏輯,而後生成的DSL如下所示:
POST task_data_1/_search
{
  "from": 0,
  "size": 10,
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "data.input18779": {
              "value": "3213",
              "boost": 1
            }
          }
        }
      ],
      "adjust_pure_negative": true,
      "boost": 1
    }
  },
  "sort": [
    {
      "createTime": {
        "order": "desc"
      }
    }
  ],
  "track_total_hits": 2147483647
}
這樣子的查詢語法,從表現上看是沒有任何問題的,但依然查不出資料。
 
後來我到kibana查詢了該索引的欄位對映關係,就是上文中的這一段json資料:
{
    "task_data_1" : {
        "mappings" : {
        "dynamic_templates" : [
            {
                "dates" : {
                "match_mapping_type" : "date",
                    "mapping" : {
                        "type" : "date"
                    }
                }
            },
            {
            "doubles" : {
                "match_mapping_type" : "double",
                "mapping" : {
                    "type" : "double"
                    }
                }
            },
            {
            "objects" : {
                "match_mapping_type" : "object",
                "mapping" : {
                    "type" : "object"
                    }
                }
            },
            {
            "longs" : {
                "match_mapping_type" : "long",
                "mapping" : {
                    "type" : "integer"
                }
                }
            },
            {
            "strings" : {
                "match" : "*",
                "match_mapping_type" : "string",
                "mapping" : {
                    "type" : "keyword"
                }
            }
            }
            ],
            "properties" : {
                "createUsername" : {
                    "type" : "keyword"
                },
                "data" : {
                    "type" : "nested",
                    "dynamic" : "true",
                    "properties" : {
                        "daterange102110" : {
                            "type" : "date"
                        },
                        "input18779" : {
                            "type" : "keyword"
                        },
                        "rate48025" : {
                            "type" : "integer"
                        },
                        "textarea24212" : {
                            "type" : "keyword"
                        },
                        "textarea38172" : {
                            "type" : "keyword"
                        },
                        "timerange47544" : {
                            "type" : "keyword"
                        },
                        "url" : {
                            "type" : "keyword"
                        }
                    }
                },
                "formId" : {
                    "type" : "long",
                    "store" : true
                },
                "updateUsername" : {
                    "type" : "keyword"
                }
            }
        }
    }
}
從這段json資料中可以發現,data這個map的型別是nested。
 
查資料後得知,在 Elasticsearch 中,"nested" 型別是一種特殊的資料型別,用於處理巢狀檔案(nested documents)。
針對這種型別的資料,需要使用 Nested Query 結合 Match Query 或 Term Query 等查詢型別來搜尋巢狀欄位。
 
因此,我對程式碼做出類似如下整改:
queryBuilder.must(QueryBuilders.nestedQuery("data", QueryBuilders.termQuery(queryFieldName, item.getFilterValue()), ScoreMode.None));
 
主要是使用到了 Nested Query,之後生成的DSL如下所示:
POST task_data_1/_search
{
  "from": 0,
  "size": 10,
  "query": {
    "bool": {
      "must": [
        {
          "nested": {
            "query": {
              "term": {
                "data.input18779": {
                  "value": "3213",
                  "boost": 1
                }
              }
            },
            "path": "data",
            "ignore_unmapped": false,
            "score_mode": "none",
            "boost": 1
          }
        }
      ],
      "adjust_pure_negative": true,
      "boost": 1
    }
  },
  "sort": [
    {
      "createTime": {
        "order": "desc"
      }
    }
  ],
  "track_total_hits": 2147483647
}
此時,對應的資料結果就能夠被查詢出來了。

總結

在 Elasticsearch 中,"nested" 型別是一種特殊的資料型別,用於處理巢狀檔案(nested documents)。
 
對於 "nested" 型別的欄位,它包含的子欄位(metadata)在查詢時需要使用特定的巢狀查詢來進行搜尋操作,簡單的查詢無法直接搜尋到巢狀欄位的內容。
以我提供的資料對映為例,資料中的 "data" map 中的每個欄位(如 "daterange102110"、 "input18779" 等)都無法直接進行搜尋,因為 Elasticsearch 預設不會對巢狀欄位進行索引。
 
如果你希望能夠對巢狀欄位進行搜尋,你需要使用巢狀查詢。例如,可以使用 Nested Query 結合 Match Query 或 Term Query 等查詢型別來搜尋巢狀欄位。

相關文章