1. 程式人生 > >ElasticSearch學習筆記之九 複雜資料型別和巢狀物件

ElasticSearch學習筆記之九 複雜資料型別和巢狀物件

複雜資料型別

除了前面說到的簡單資料型別,Elasticsearch還支援JSON 的null ,陣列,和物件.

空域

欄位取值可以為空,當然,陣列也可以為空。 然而,在 Lucene 中是不能儲存 null 值的,所以我們認為存在 null 值的域為空域。

下面三種域被認為是空的,它們將不會被索引:

"null_value":               null,
"empty_array":              [],
"array_with_null_value":    [ null ]

陣列域

很多時候,我們希望 tag 域 包含多個標籤。我們可以以陣列的形式索引標籤:

{
"tag": [ "search", "nosql" ]}

對於陣列,沒有特殊的對映需求。任何域都可以包含0、1或者多個值,就像全文域分析得到多個詞條。

這暗示 陣列中所有的值必須是相同資料型別的 。你不能將日期和字串混在一起。如果你通過索引陣列來建立新的域,Elasticsearch 會用陣列中第一個值的資料型別作為這個域的 型別 。

注意:
當你從 Elasticsearch 得到一個文件,每個陣列的順序和你當初索引文件時一樣。你得到的 _source 域,包含與你索引的一模一樣的 JSON 文件。

但是,陣列是以多值域 索引的—可以搜尋,但是無序的。 在搜尋的時候,你不能指定 “第一個” 或者 “最後一個”。 更確切的說,把陣列想象成 裝在袋子裡的值 。

多層級物件

內部物件 經常用於嵌入一個實體或物件到其它物件中。例如,與其在 tweet 文件中包含 user_name 和 user_id 域,我們也可以這樣寫:

{
    "tweet":            "Elasticsearch is very flexible",
    "user": {
        "id":           "@johnsmith",
        "gender":       "male",
        "age":          26,
        "name": {
            "full":     "John Smith"
, "first": "John", "last": "Smith" } } }

內部物件的對映

Elasticsearch 會動態監測新的物件域並對映它們為 物件 ,在 Elasticsearch 6之前properties 屬性下列出內部域:

{
  "gb": {
    "tweet": 
      "properties": {
        "tweet":            { "type": "string" },
        "user": {
          "type":             "object",
          "properties": {
            "id":           { "type": "string" },
            "gender":       { "type": "string" },
            "age":          { "type": "long"   },
            "name":   { 
              "type":         "object",
              "properties": {
                "full":     { "type": "string" },
                "first":    { "type": "string" },
                "last":     { "type": "string" }
              }
            }
          }
        }
      }
    }
  }
}

user 和 name 域的對映結構與 tweet 型別的相同。事實上, type 對映只是一種特殊的 物件 對映,我們稱之為 根物件 。除了它有一些文件元資料的特殊頂級域,例如 _source 和 _all 域,它和其他物件一樣。

注:
elasticsearch6以後沒有object型別了,預設巢狀處理了。elasticsearch6以後對映查詢結果如下:

{
  "test": {
    "mappings": {
      "test": {
        "properties": {
          "tweet": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "user": {
            "properties": {
              "age": {
                "type": "long"
              },
              "gender": {
                "type": "text",
                "fields": {
                  "keyword": {
                    "type": "keyword",
                    "ignore_above": 256
                  }
                }
              },
              "id": {
                "type": "text",
                "fields": {
                  "keyword": {
                    "type": "keyword",
                    "ignore_above": 256
                  }
                }
              },
              "name": {
                "properties": {
                  "first": {
                    "type": "text",
                    "fields": {
                      "keyword": {
                        "type": "keyword",
                        "ignore_above": 256
                      }
                    }
                  },
                  "full": {
                    "type": "text",
                    "fields": {
                      "keyword": {
                        "type": "keyword",
                        "ignore_above": 256
                      }
                    }
                  },
                  "last": {
                    "type": "text",
                    "fields": {
                      "keyword": {
                        "type": "keyword",
                        "ignore_above": 256
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

內部物件的索引

Lucene 不支援內部物件。 Lucene 文件是由一組鍵值對列表組成的。為了能讓 Elasticsearch 有效地索引內部類,它把我們的文件轉化成這樣:

{
    "tweet":            [elasticsearch, flexible, very],
    "user.id":          [@johnsmith],
    "user.gender":      [male],
    "user.age":         [26],
    "user.name.full":   [john, smith],
    "user.name.first":  [john],
    "user.name.last":   [smith]
}

內部域 可以通過名稱引用(例如, first )。為了區分同名的兩個域,我們可以使用全 路徑 (例如, user.name.first ) 或 type 名加路徑( tweet.user.name.first )。

在前面簡單扁平的文件中,沒有 user 和 user.name 域。Lucene 索引只有標量和簡單值,沒有複雜資料結構。

內部物件陣列

假設我們有個 followers 內部物件陣列:

{
    "followers": [
        { "age": 35, "name": "Mary White"},
        { "age": 26, "name": "Alex Jones"},
        { "age": 19, "name": "Lisa Smith"}
    ]
}

這個文件會像我們之前描述的那樣被扁平化處理,結果如下所示:

{
    "followers.age":    [19, 26, 35],
    "followers.name":   [alex, jones, lisa, smith, mary, white]
}

但是這裡有一個問題,{age: 35}{name: Mary White}之間的相關性已經丟失了,因為每個多值域只是一包無序的值,而不是有序陣列。這足以讓我們問,“有一個26歲的追隨者?”

但是我們不能得到一個準確的答案:“是否有一個26歲 名字叫 Alex Jones 的追隨者?”

巢狀物件

考慮到上面內部物件陣列的問題,我們看下面的例子:

由於在 Elasticsearch 中單個文件的增刪改都是原子性操作,那麼將相關實體資料都儲存在同一文件中也就理所當然。 比如說,我們可以將訂單及其明細資料儲存在一個文件中。又比如,我們可以將一篇部落格文章的評論以一個 comments 陣列的形式和部落格文章放在一起:

PUT /my_index/blogpost/1
{
  "title": "Nest eggs",
  "body":  "Making your money work...",
  "tags":  [ "cash", "shares" ],
  "comments": [ 
    {
      "name":    "John Smith",
      "comment": "Great article",
      "age":     28,
      "stars":   4,
      "date":    "2014-09-01"
    },
    {
      "name":    "Alice White",
      "comment": "More like this please",
      "age":     31,
      "stars":   5,
      "date":    "2014-10-22"
    }
  ]
}

如果我們依賴欄位自動對映,那麼 comments 欄位會自動對映為 object 型別。

由於所有的資訊都在一個文件中,當我們查詢時就沒有必要去聯合文章和評論文件,查詢效率就很高。

但是當我們使用如下查詢時,上面的文件也會被當做是符合條件的結果:

GET /my_index/blogpost/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "name": "Alice" }},
        { "match": { "age":  28      }} 
      ]
    }
  }
}

Alice實際是31歲,不是28!
注:
elasticsearch6之後的版本沒有整個問題,被解決了,6之後的查詢結果沒有命中,結果如下:

{
  "took": 0,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 0,
    "max_score": null,
    "hits": []
  }
}

正如我們在 物件陣列 中討論的一樣,出現上面這種問題的原因是 JSON 格式的文件被處理成如下的扁平式鍵值對的結構。

{
  "title":            [ eggs, nest ],
  "body":             [ making, money, work, your ],
  "tags":             [ cash, shares ],
  "comments.name":    [ alice, john, smith, white ],
  "comments.comment": [ article, great, like, more, please, this ],
  "comments.age":     [ 28, 31 ],
  "comments.stars":   [ 4, 5 ],
  "comments.date":    [ 2014-09-01, 2014-10-22 ]
}

Alice 和 31 、 John 和 2014-09-01 之間的相關性資訊不再存在。雖然 object 型別 (參見 內部物件) 在儲存 單一物件 時非常有用,但對於物件陣列的搜尋而言,毫無用處。

巢狀物件 就是來解決這個問題的。將 comments 欄位型別設定為 nested 而不是 object 後,每一個巢狀物件都會被索引為一個 隱藏的獨立文件 ,舉例如下:

{ #第一個 巢狀文件
  "comments.name":    [ john, smith ],
  "comments.comment": [ article, great ],
  "comments.age":     [ 28 ],
  "comments.stars":   [ 4 ],
  "comments.date":    [ 2014-09-01 ]
}
{ #第二個 巢狀文件
  "comments.name":    [ alice, white ],
  "comments.comment": [ like, more, please, this ],
  "comments.age":     [ 31 ],
  "comments.stars":   [ 5 ],
  "comments.date":    [ 2014-10-22 ]
}
{ #根文件 或者也可稱為父文件
  "title":            [ eggs, nest ],
  "body":             [ making, money, work, your ],
  "tags":             [ cash, shares ]
}

在獨立索引每一個巢狀物件後,物件中每個欄位的相關性得以保留。我們查詢時,也僅僅返回那些真正符合條件的文件。

不僅如此,由於巢狀文件直接儲存在文件內部,查詢時巢狀文件和根文件聯合成本很低,速度和單獨儲存幾乎一樣。

巢狀文件是隱藏儲存的,我們不能直接獲取。如果要增刪改一個巢狀物件,我們必須把整個文件重新索引才可以。值得注意的是,查詢的時候返回的是整個文件,而不是巢狀文件本身。

巢狀物件對映

設定一個欄位為 nested 很簡單 —  你只需要將欄位型別 object 替換為 nested 即可:


PUT /my_index
{
  "mappings": {
    "blogpost": {
      "properties": {
        "comments": {
          "type": "nested", 
          "properties": {
            "name":    { "type": "string"  },
            "comment": { "type": "string"  },
            "age":     { "type": "short"   },
            "stars":   { "type": "short"   },
            "date":    { "type": "date"    }
          }
        }
      }
    }
  }
}

相關推薦

ElasticSearch學習筆記 複雜資料型別物件

複雜資料型別 除了前面說到的簡單資料型別,Elasticsearch還支援JSON 的null ,陣列,和物件. 空域 欄位取值可以為空,當然,陣列也可以為空。 然而,在 Lucene 中是不能儲存 null 值的,所以我們認為存在 null 值的域為空域。

Java學習筆記——變數與資料型別

一、變數 1.變數:變化的值 變數在程式碼執行期間,開闢了一塊空間 。這塊空間是有地址的,給這塊取了個名字, 這個名字就叫做變數名,這塊空間放的東西叫做變數值   2.變數的初始化: (1)先宣告再賦值: ***宣告變數:資料型別 變數名*** 宣告:int i; 賦值:i=1;

《瘋狂Java講義》學習筆記(三)資料型別運算子

1、註釋 Java語言的註釋一共有三種類型 單行註釋:用雙斜線 ”//” 表示 多行註釋:用 /*------------------*/ 表示 文件註釋:用 /**-----------------*/ 表示 如果編寫Java原始碼時添加了合適的文件註釋,然後通過JDK提供的jav

Hive程式設計指南-學習筆記(一) 資料型別分隔符

一、Hive概述 Hive定義了類似SQL的查詢語言——HiveQL,使用者編寫HiveQL語句執行MapReduce任務,查詢儲存在Hadoop叢集中的資料。 HiveQL與MySQL最接近,但還是有顯著性差異的。Hive不支援行級插入、更新操作和刪除操作。Hive不支

ElasticSearch學習筆記三十三 IK分詞器擴充套件字典及text全文型別資料分詞聚合查詢

ElasticSearch學習筆記之三十三 IK分詞器擴充套件字典及text全文型別資料分詞聚合查詢 專屬詞彙分詞失敗 擴充套件字典 檢視當前詞庫 自定義詞典 更新配置 再次檢視分詞 text全文型別資料分詞聚合

ElasticSearch學習筆記二十 Java REST Client

ElasticSearch學習筆記之二十九 Java REST Client Java REST Client Java High Level REST Client Compatibility(相容性) Javadoc Maven Reposi

ElasticSearch學習筆記二十 JAVA Client GET APIs

Get API Get Request GetRequest形如: GetRequest getRequest = new GetRequest( "posts", //Index "doc", //Type

ceph學習筆記 層級化的Cluster Map

sds ceph.crush 集群映射由Device和桶(Buckets)組成,設備和桶都有ID描述和權重。Bucket可以包含任意設備或者其他的bucket,使他們形成內部節點的存儲層次結構,設備總是在葉子節點。存儲設備的權重由管理員設置以控制設備負責存儲的相對數據量。盡管大型系統的設備含不同的容量

Elasticsearch學習筆記)partial update

cse adding 操作 nbsp 進行 樂觀 gin clas 比較 一、什麽是partial update? PUT /index/type/id,創建文檔&替換文檔,就是一樣的語法 一般對應到應用程序中,每次的執行流程基本是這樣的: (1)應

Linux學習筆記————ubuntu軟件安裝與卸載

升級 獲取 tor mage 技術 png bsp and rem 一、更新 源 1. 尋找國內鏡像源 所謂的鏡像源:可以理解為提供下載軟件的地方,比如Android手機上可以下載軟件的91手機助手;iOS手機上可以下載軟件的AppStore 2. 備份Ubuntu

Memcached學習筆記:memcached問題彙集

這裡收集了經常被問到的關於memcached的問題 memcached是怎麼工作的? memcached最大的優勢是什麼? memcached和MySQL的query cache相比,有什麼優缺點? memcached和伺服器的local cache(比如PHP的APC、

Golang學習筆記(四)資料型別轉換

整數型別和浮點型別的轉換,先申明兩個變數,一個是int型的,一個是float型的。 chinese := 90 english := 80.9 將int型的強轉為float型,可以使用float32()或float64(),如float32(int型變數) avg1 := (floa

Golang學習筆記(二)資料型別

Go的資料型別與Java等語言的資料型別幾乎一致 //byte其實就是uint8的別名 var aaa byte = 100 // rune其實就是int32的別名 var bbb rune = 200 //可以給一個字元,計算ascll碼 var ddd byte = 'a' var c

廖雪峰JavaScript學習筆記(基礎及資料型別、變數)

先睹為快 alert('我要學JavaScript!'); Run: 基本語法: 1.每個語句以;結束,不強制 2.語句塊用{...} 3.//單行註釋,/*...*/ 多行註釋 資料型別: 1.不區分整數,浮點數,統一用number~ 以下也屬於number型別~ NaN;

ElasticSearch學習筆記二十八 細說Pipeline Aggregations

ElasticSearch學習筆記之二十八 細說Pipeline Aggregations Avg Bucket Aggregation(平均值分組聚合) Syntax(語法) avg_bucket 引數 Max Bucket Ag

ElasticSearch學習筆記二十七 Pipeline Aggregations

ElasticSearch學習筆記之二十七 Pipeline Aggregations Pipeline Aggregations buckets_path 語法 Special Paths(特殊路徑) Dealing with dots

ElasticSearch學習筆記三十二 JAVA Client Exists Delete Update APIs

ElasticSearch學習筆記之三十二 JAVA Client 之 Exists Delete Update APIs Exists API Exists Request Synchronous Execution(同步執行) Asy

ElasticSearch學習筆記三十一 JAVA Client GET APIs

ElasticSearch學習筆記之三十一 JAVA Client 之 GET APIs Get API Get Request Optional arguments(引數配置) Synchronous Execution(同步執行)

ElasticSearch學習筆記三十 JAVA Client Document APIs

ElasticSearch學習筆記之三十 JAVA Client 之 文件請求概述 Document APIs(文件APIS) Index API Index Request(索引請求) Providing the document sou

ElasticSearch學習筆記二十二 指標聚合續

ElasticSearch學習筆記之二十二 指標聚合續 Max Aggregation Min Aggregation Percentiles Aggregation Stats Aggregation Sum Aggregation Va