ES 筆記四十二:物件及 Nested 物件

CrazyZard發表於2020-01-05
  • 真實世界中很多重要的關聯關係
    • 部落格、作者、評論
    • 銀行賬戶有多次交易記錄
    • 客戶有很多銀行賬戶
    • 目錄檔案有很多檔案和子目錄
  • 正規化化設計(Normalization)的主要目標是“減少不必要的更新”
  • 副作用:一個完全正規化化設計的資料庫經常面臨“查詢緩慢”的問題
    • 資料庫餘額正規化化,就需要Join越多的表
  • 正規化化節省了儲存空間,但是儲存空間越來越便宜
  • 正規化化簡化了更新,但是資料“讀”取操作可能越多
  • ES筆記四十二:物件及 Nested 物件

  • 反正規化化設計
    • 資料“Flattening”,不使用關聯關係,而是在文件中儲存冗餘的資料拷貝
  • 優點:無需處理Joins操作,資料讀取效能好
    • Elasticsearch 通過壓縮_source欄位,減少磁碟空間的開銷
  • 缺點:不適合在資料頻繁修改的場景
    • 一條資料(使用者名稱)的改動,可能會引起很多資料的更新
  • 關係型資料庫,一般會考慮 Normalize 資料;在Elasticsearch,往往考慮 Denormalize 資料
    • Denormalize 的好處:讀的速度變快、無需表連線、無需行鎖
  • Elasticsearch 並不擅長處理關聯關係,我們一般採用以下四種方法處理關聯
    • 物件型別
    • 巢狀物件(Nested Object)
    • 父子關聯關係(Parent 、Child)
    • 應用端關聯

案例1:部落格和其作者資訊

  • 物件型別
    • 在每個部落格的問下中都保留作者的資訊
    • 如果作者資訊發生變化,需要修改相關的部落格文件
PUT /blog
{
  "mappings": {
    "properties": {
      "content": {
        "type": "text"
      },
      "time": {
        "type": "date"
      },
      "user": {
        "properties": {
          "city": {
            "type": "text"
          },
          "userid": {
            "type": "long"
          },
          "username": {
            "type": "keyword"
          }
        }
      }
    }
  }
}

# 插入一條 Blog 資訊
PUT blog/_doc/1
{
  "content":"I like Elasticsearch",
  "time":"2019-01-01T00:00:00",
  "user":{
    "userid":1,
    "username":"Jack",
    "city":"Shanghai"
  }
}
  • 通過一條查詢語句即可獲取到部落格和作者資訊
    # 查詢 Blog 資訊
    POST blog/_search
    {
    "query": {
    "bool": {
      "must": [
        {"match": {"content": "Elasticsearch"}},
        {"match": {"user.username": "Jack"}}
      ]
    }
    }
    }

ES筆記四十二:物件及 Nested 物件

案例2:包含物件陣列的文件

# 電影的Mapping資訊
PUT my_movies
{
      "mappings" : {
      "properties" : {
        "actors" : {
          "properties" : {
            "first_name" : {
              "type" : "keyword"
            },
            "last_name" : {
              "type" : "keyword"
            }
          }
        },
        "title" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
}

# 寫入一條電影資訊
POST my_movies/_doc/1
{
  "title":"Speed",
  "actors":[
    {
      "first_name":"Keanu",
      "last_name":"Reeves"
    },

    {
      "first_name":"Dennis",
      "last_name":"Hopper"
    }

  ]
}
# 查詢電影資訊
POST my_movies/_search
{
  "query": {
    "bool": {
      "must": [
        {"match": {"actors.first_name": "Keanu"}},
        {"match": {"actors.last_name": "Hopper"}}
      ]
    }
  }
}

ES筆記四十二:物件及 Nested 物件

  • 儲存時,內部物件的邊界沒有在考慮在內,JSON格式被處理成扁平鍵值對的結構
  • 當對多個欄位進行查詢時,導致了意外的搜尋結果
  • 可以用 Nested Data Type 解決這個問題
  • Nested 資料型別:允許物件陣列中的物件唄獨立索引
  • 使用 Nested 和 Properties 關鍵詞,將所有 actors 索引到對個分隔的文件
  • 在內部,Nested 文件會被儲存在兩個 Lucene 文件中,查詢時做join處理
PUT my_movies
{
      "mappings" : {
      "properties" : {
        "actors" : {
          "type": "nested",
          "properties" : {
            "first_name" : {"type" : "keyword"},
            "last_name" : {"type" : "keyword"}
          }},
        "title" : {
          "type" : "text",
          "fields" : {"keyword":{"type":"keyword","ignore_above":256}}
        }
      }
    }
}
  • 在內部,Nested 文件被儲存在兩個Lucene 文件中

ES筆記四十二:物件及 Nested 物件

# Nested 查詢
POST my_movies/_search
{
  "query": {
    "bool": {
      "must": [
        {"match": {"title": "Speed"}},
        {
          "nested": {
            "path": "actors",
            "query": {
              "bool": {
                "must": [
                  {"match": {
                    "actors.first_name": "Keanu"
                  }},
                  {"match": {
                    "actors.last_name": "Hopper"
                  }}
                ]
              }
            }
          }
        }
      ]
    }
  }
}
//返回
 "hits" : {
    "total" : {
      "value" : 0,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  }
# Nested Aggregation
POST my_movies/_search
{
  "size": 0,
  "aggs": {
    "actors": {
      "nested": {
        "path": "actors"
      },
      "aggs": {
        "actor_name": {
          "terms": {
            "field": "actors.first_name",
            "size": 10
          }
        }
      }
    }
  }
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結

快樂就是解決一個又一個的問題!

相關文章