Elasticsearch核心技術與實戰學習筆記 49 | 對象及Nested對象

一 序

  本文屬於極客時間Elasticsearch核心技術與實戰學習筆記系列。

二 數據的關聯關係

真實世界中有很多關係,軟件也是對此一種抽象。

2.1關係型數據庫的範式化設計  

範式化設計(Normalization)的主要目標是 “減少不必要的更新”
副作用:一個完全範式化設計的數據庫經常面臨 “查詢緩慢” 的問題

  • 數據庫餘額範式化,就需要 Join 越多的表

範式化節省了儲存空間,但是儲存空間越來越便宜
範式化簡化了更新,但是數據 “讀” 取操作可能越多

2.2Denormalization

 反範式化設計

  • 數據 “Flattening”, 不使用關聯關係,而是在文檔中保存冗餘的數據拷貝

優點:無需處理 Joins 操作,數據讀取性能好

  • Elasticsearch 通過壓縮_source 字段,減少磁盤空間的開銷

缺點:不適合在數據頻繁修改的場景

  • 一條數據(用戶名)的改動,可能會引起很多數據的更新

2.3 在 Elasticsearch 中處理關聯關係

關係型數據庫,一般會考慮 Normalize 數據;在 Elasticsearch,往往考慮 Denormalize 數據

  • Denormalize 的好處:讀的速度變快、無需表連接、無需行鎖

Elasticsearch 並不擅長處理關聯關係,我們一般採用以下四種方法處理關聯

  • 對象類型
  • 嵌套對象(Nested Object)
  • 父子關聯關係(Parent 、Child)
  • 應用端關聯

案例 1:博客和其作者信息

數據準備:

DELETE blog
# 設置blog的 Mapping
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"
  }
}

這是bool的query,es滿足搜索需求。

案例 2:包含對象數組的文檔

數據準備:

DELETE my_movies

# 電影的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"
    }

  ]
}

查詢到數據,但是不存在滿足查詢條件的數據。

爲啥搜到不需要的數據?

  • 儲存時,內部對象的邊界沒有在考慮在內,JSON 格式被處理成扁平鍵值對的結構
  • 當對多個字段進行查詢時,導致了意外的搜索結果
  • 可以用 Nested Data Type 解決這個問題

Nested Data Type

  •  Nested 數據類型:允許對象數組中的對象被獨立索引
  • 使用 Nested 和 Properties 關鍵詞,將所有 actors 索引到對個分隔的文檔
  • 在內部,Nested 文檔會被保存在兩個 Lucene 文檔中,查詢時做 join 處理

數據準備:

DELETE my_movies
# 創建 Nested 對象 Mapping
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}}
        }
      }
    }
}


POST my_movies/_doc/1
{
  "title":"Speed",
  "actors":[
    {
      "first_name":"Keanu",
      "last_name":"Reeves"
    },

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

這個索引增加了    "type": "nested",指定爲嵌套的對象。

3 嵌套查詢

在內部,Nested 文檔被保存在兩個 Lucene 文檔中

上面指定嵌套關鍵字:nested,path指定屬性。下面增加actor_name做子聚合。就可以實現嵌套對象的term分桶。

# 普通 aggregation不工作
POST my_movies/_search
{
  "size": 0,
  "aggs": {
    "NAME": {
      "terms": {
        "field": "actors.first_name",
        "size": 10
      }
    }
  }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章