您好,登錄后才能下訂單哦!
??ES中的映射(Mapping)實(shí)質(zhì)上就是對(duì)文檔對(duì)象結(jié)構(gòu)的定義,也即對(duì)文檔中各元素的描述。在ES中定義映射,就如同定義XML文檔的XML Schema。
??ES中的映射定義了文檔模式(就如同在關(guān)系數(shù)據(jù)庫中定義了關(guān)系模式),文檔模式確定了存在ES中的文檔的格式,結(jié)構(gòu)和字段的數(shù)據(jù)類型。通過查看某個(gè)索引的映射可以了解文檔的結(jié)構(gòu),以便使用查詢語言(Query DSL)構(gòu)建更符合我們要求的查詢命令。
??讓我們首先看一下如下關(guān)于銀行賬號(hào)的文檔示例:
{
"account_number": 1,
"balance": 39225,
"firstname": "Amber",
"lastname": "Duke",
"age": 32,
"gender": "M",
"address": "880 Holmes Lane",
"employer": "Pyrami",
"email": "amberduke@pyrami.com",
"city": "Brogan",
"state": "IL"
}
??ES對(duì)該文檔的自動(dòng)生成的映射是下面這個(gè)樣子的:
{
"bank": {
"mappings": {
"account": {
"properties": {
"account_number": {
"type": "long"
},
"address": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"age": {
"type": "long"
},
"balance": {
"type": "long"
},
"city": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"email": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"employer": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"firstname": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"gender": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"lastname": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"state": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
}
}
}
??由這個(gè)自動(dòng)生成的映射可以看到:ES自動(dòng)將account_number、balance、age這些屬性映射為long類型,其它的屬性都映射為text類型。text類型的屬性常用于全文搜索,但是并不進(jìn)入內(nèi)存中索引,因此text類型并不可用于聚合和排序(系統(tǒng)會(huì)報(bào)錯(cuò):"Fielddata is disabled on text fields by default. Set fielddata=true on [address] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory. Alternatively use a keyword field instead.")。
??ES允許為一個(gè)對(duì)象屬性定義多個(gè)域(fields),每個(gè)域是該屬性的一個(gè)facet(我思考很久,還是覺得這個(gè)詞最合適),如“address”屬性類型為text,為它定義 一個(gè)域?yàn)閗eyword,該域的類型為“keyword”,不會(huì)被分析器(analyzer)分析,可用于排序、聚合和精確查找(請(qǐng)注意ignore_above這個(gè)屬性,限制了用于keyword的有效字符數(shù)目)。
??在DSL查詢語言中查詢時(shí),使用“address”時(shí),經(jīng)分析器分析后,"880 Holmes Lane"可能被分解為“880”,“Holmes”,“Lane”進(jìn)入全文搜索。看看下面的兩個(gè)查詢命令:
curl -iXGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d'
{"query":
{"match":
{"address.keyword":"880 Holmes Lane"}
}
}'
??查詢出來只有一個(gè)結(jié)果,精確匹配“880 Holmes Lane”。
curl -iXGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d'
{"query":
{"match":
{"address":"880 Holmes Lane"}
}
}'
??查詢出來多個(gè)結(jié)果,查詢條件“880 Holmes Lane”被分析器分析后檢索,"591 Nolans Lane"也被檢索出來(其中包含了一個(gè)分析器分解后的Lane)。
??以一張圖總結(jié)相關(guān)的知識(shí)點(diǎn):
??ES中域的主要數(shù)據(jù)類型如下表所示,還可由一些插件擴(kuò)展數(shù)據(jù)類型(這里不贅述了):
數(shù)據(jù)類型 | 分類 |
---|---|
text , keyword | 字符串 |
long , integer , short , byte , double , float , half_float , scaled_float | 數(shù)字 |
date | 日期 |
boolean | 布爾 |
binary | 二進(jìn)制 |
integer_range , float_range , long_range , double_range , date_range | 區(qū)間類型 |
Array, object, nested | 復(fù)雜數(shù)據(jù)類型 |
geo_point, geo_shape | 地理數(shù)據(jù)類型 |
binary | 二進(jìn)制 |
ip, completion,token_count,percolator,join, alias | 特殊數(shù)據(jù)類型 |
??核心數(shù)據(jù)類型與我們常使用的強(qiáng)類型語言中的數(shù)據(jù)類型類似,可分為以下幾類:
//類型為integer_range
"expected_attendees" : {
"gte" : 10,
"lte" : 20
}
??對(duì)于日期區(qū)間類型,示例如下:
//類型為date_range
"time_frame" : {
"gte" : "2015-10-31 12:00:00",
"lte" : "2015-11-01"
}
??復(fù)雜數(shù)據(jù)類型可用于表達(dá)對(duì)象之間的語義,包含Array, object, nested等類型。
"manager": {
"properties": {
"age": { "type": "integer" },
"name": {
"properties": {
"first": { "type": "text" },
"last": { "type": "text" }
}
}
}
}
??其對(duì)應(yīng)的對(duì)象為:
"manager": {
"age": 30,
"name": {
"first": "John",
"last": "Smith"
}
}
??其中域manager就是一個(gè)對(duì)象類型,其中的name是它的子對(duì)象。對(duì)于對(duì)象類型,缺省設(shè)置“type”為”object”,因此不用顯式定義“type”。
??對(duì)于上面的對(duì)象類型,ES在索引時(shí)將其轉(zhuǎn)換為"manager.age", "manager.name.first" 這樣扁平的key,因此查詢時(shí)也可以使用這樣的扁平key作為域來進(jìn)行查詢。
"user" : [
{
"first" : "John",
"last" : "Smith"
},
{
"first" : "Alice",
"last" : "White"
}
]
??如果使用動(dòng)態(tài)映射,會(huì)被ES索引為如下形式:
"user.first" : [ "alice", "john" ],
"user.last" : [ "smith", "white" ]
??這樣的索引形式在查詢時(shí)會(huì)丟失對(duì)象中”first”與“l(fā)ast”之間的關(guān)聯(lián)關(guān)系。
??如果將user映射為如下形式:
"user": {
"type": "nested"
}
??ES在索引時(shí)會(huì)保留對(duì)象域之間的關(guān)聯(lián)關(guān)系,在查詢時(shí)找對(duì)正確的對(duì)象。
??如使用如下查詢則找不到任何命中對(duì)象(不存在“Alice Smith”這個(gè)對(duì)象):
{
"query": {
"nested": {
"path": "user",
"query": {
"bool": {
"must": [
{ "match": { "user.first": "Alice" }},
{ "match": { "user.last": "Smith" }}
]
}
}
}
}
}
??地理數(shù)據(jù)類型可用于LBS的應(yīng)用,包括:
// location為geo_point類型
"location": {
"lat": 41.12,
"lon": -71.34
}
??特殊數(shù)據(jù)類型包括:
{
"my_join_field": {
"type": "join",
"relations": {
"question": "answer"
}
}
}
??my_join_field定義了"question"與"answer"之間關(guān)系為父子關(guān)系。
??觀察對(duì)于該映射的一個(gè)文檔實(shí)例,路徑為“my_index/_doc/1”:
{
"text": "This is a question",
"my_join_field": "question"
}
??該文檔的一個(gè)子文檔對(duì)象示例如下,在my_join_field需要定義父親的ID(這里根據(jù)上面的父實(shí)例,為1):
{
"text": "This is an answer",
"my_join_field": {
"name": "answer",
"parent": "1"
}
}
??需要注意的是,一個(gè)父文檔可以有多個(gè)子文檔,父子文檔應(yīng)部署在同一個(gè)分片上。因而在向ES提交父子文檔時(shí),應(yīng)在URI中使用相同的routing參數(shù)。
??join類型定義了文檔之間的父子依賴關(guān)系,在查詢和聚合操作中可使用這種依賴關(guān)系。
??JSON是JS對(duì)象序列化的字符串,ES接收一個(gè)JSON字符串形式的文檔對(duì)象,本質(zhì)上是存入一個(gè)JS對(duì)象,JS定義了對(duì)象,數(shù)組,字符串,數(shù)字,布爾型和null等數(shù)據(jù)類型。
??ES中的域數(shù)據(jù)類型可視為對(duì)JS對(duì)象數(shù)據(jù)類型的擴(kuò)展,如join,區(qū)間類型等都表示為js對(duì)象。
??在定義域映射時(shí),ES定義了相關(guān)的映射參數(shù),這里簡(jiǎn)單列舉并描述,詳細(xì)信息可以查看文獻(xiàn)1。
參數(shù) | 描述 |
---|---|
analyzer | 定義對(duì)文本數(shù)據(jù)的分析器 |
normalizer | 對(duì)文本數(shù)據(jù)規(guī)范化 |
boost | 用于提升字段搜索的權(quán)重 |
coerce | 當(dāng)為false時(shí),強(qiáng)制輸入值必須符合映射的域數(shù)據(jù)類型 |
copy_to | 將當(dāng)前域的值復(fù)制到另一個(gè)域中 |
doc_values | 當(dāng)該域不參與排序域聚合操作時(shí),可設(shè)置為false使得不在磁盤上存儲(chǔ)Doc value(以列式存儲(chǔ)的文檔值)以節(jié)約磁盤空間。缺省為true |
dynamic | 該參數(shù)控制在對(duì)象中檢測(cè)到的新的域(未在映射中定義)是否加入到域中,當(dāng)為false或strict時(shí),新域不會(huì)加入到映射中。缺省為true |
enabled | 主要應(yīng)用于object類型的域,當(dāng)設(shè)置為false,該域不被索引。缺省為true |
fielddata | 對(duì)于text類型的域,如果該參數(shù)設(shè)置為true,該域的數(shù)據(jù)在第一次使用時(shí)會(huì)載入常駐于內(nèi)存中。缺省為false |
format | 定義域數(shù)據(jù)的格式,用于日期類型 |
ignore_above | 定義字符串的有效長(zhǎng)度 |
ignore_malformed | 如果設(shè)置為true,當(dāng)字段值與映射定義不一致時(shí),不會(huì)拋出錯(cuò)誤。缺省為false |
index | 缺省為true,當(dāng)設(shè)置為false時(shí),該域不被索引,不可被搜索 |
null_value | 定義該域?yàn)榭罩禃r(shí)的格式,如使用“NULL”這樣的字符串 |
search_analyzer | 定義搜索時(shí)的analyzer,可與定義映射時(shí)使用的analyzer不同 |
store | 該值設(shè)置為true時(shí),當(dāng)前域的原始值也存儲(chǔ)下來(在_source之外)。默認(rèn)為false |
??總結(jié)一下:
??在ES中設(shè)計(jì)一個(gè)索引的映射和在關(guān)系數(shù)據(jù)庫中設(shè)計(jì)關(guān)系模式,ER模型,在XML中設(shè)計(jì)XML Schema一樣。需要完整包含領(lǐng)域知識(shí)并滿足數(shù)據(jù)之間的約束。
??在這一節(jié)中我們探討一個(gè)使用ES構(gòu)建視頻圖像信息數(shù)據(jù)庫的實(shí)例。
??視頻圖像信息數(shù)據(jù)庫(以下簡(jiǎn)稱視圖庫)基于GA/T 1400.3 標(biāo)準(zhǔn)定義,用于存儲(chǔ)視頻、圖像等基本對(duì)象(二進(jìn)制數(shù)據(jù))和由這些基本對(duì)象分析(可自動(dòng))出的屬性對(duì)象。
??在GA/T 1400.4中,定義了訪問視頻圖像信息數(shù)據(jù)庫的接口,這些接口以基于HTTP的restful形式定義,以JSON格式傳輸數(shù)據(jù)。因而使用ES作為視頻圖像信息數(shù)據(jù)庫的存儲(chǔ)容器可以利用ES的JSON文檔對(duì)象存儲(chǔ)和。
??在GA/T 1400.3中定義了視頻圖像信息數(shù)據(jù)庫的數(shù)據(jù)模型,該數(shù)據(jù)模型中定義了三十多個(gè)領(lǐng)域?qū)ο?,?duì)象之間具有關(guān)聯(lián)關(guān)系。視圖庫中的對(duì)象定義主要包含以下特征:
??視圖庫規(guī)范定義對(duì)象字段的數(shù)據(jù)類型可為:
??以視圖庫中的File對(duì)象(GA/T 1400.3附錄A.7)為例,我們看看如何定義它的映射。
??在GA/T 1400.3中,它的XML Schema是這樣定義的:
<complexType name="File">
<sequence>
<element name="FileID" type=" BasicObjectIdType"/>
<element name="InfoKind" type="InfoType" use="required"/>
<element name="Source" type="DataSourceType" use="required"/>
<element name="FileName" type="FileNameType" use="required"/>
<element name="StoragePath" type="string" />
<element name="FileHash" type="string" use="required"/>
<element name="FileFormat" type="string" use="required"/>
<element name="Title" type="string" use="required"/>
<element name="SecurityLevel" type="SecretLevelType" />
<element name="SubmiterName" type="NameType" />
<element name="SubmiterOrg" type="string" />
<element name="EntryTime" type="dateTime" />
<element name="FileSize" type="int"/>
</sequence>
</complexType>
??一個(gè)文件對(duì)象的對(duì)象實(shí)例如下所示。
{
"FileObject": {
"FileID": "31000000001190000138022019021416121100001",
"InfoKind": 1,
"Source": "3",
"FileName": "tollgate_3_lane_4_20190214161211.jpg",
"StoragePath": "/tollgate/3/lane/4/images",
"FileHash": "38b8c2c1093dd0fec383a9d9ac940515",
"FileFormat": "Jpeg",
"Title": "tollgate_3_lane_4_20190214161211",
"SecurityLevel": "3",
"SubmiterName": "zhangkai",
"SubmiterOrg": "pudong",
"EntryTime": "20190214161214",
"FileSize": 94208
}
}
??分析該對(duì)象中的各屬性字段,整理出下表:
字段名稱 | 標(biāo)準(zhǔn)中的數(shù)據(jù)類型定義 | ES中對(duì)應(yīng)類型 | 備注 |
---|---|---|---|
FileID | string(41) | type:keyword <br> doc_values:false <br>ignore_above : 41 | 不參與排序與聚合 |
InfoKind | int | type: integer<br>coerce: false | |
Source | string(2) | type:keyword<br> ignore_above : 2 | |
FileName | string(0..256) | type:keyword<br>ignore_above : 256 | |
StoragePath | string(256) | type:keyword<br>doc_values:false<br>ignore_above : 256 | 不參與排序與聚合 |
FileHash | string(32) | type:keyword<br>doc_values:false<br> ignore_above : 32 | 不參與排序與聚合 |
FileFormat | string(32) | type:keyword<br>ignore_above : 32 | |
Title | string(128) | type:keyword <br>ignore_above : 128 | |
SecurityLevel | String(1) | type:keyword<br> ignore_above : 1 | |
SubmiterName | string(0..50) | type:keyword <br>ignore_above : 50 | |
SubmiterOrg | string(0..100) | type:keyword <br>ignore_above : 100 | |
EntryTime | dateTime | type: date <br>format:yyyyMMddHHmmss | 格式為:YYYYMMDDhhmmss |
FileSize | int | type: integer <br> coerce: false |
??我們使用如下命令在ES中創(chuàng)建索引file(注意這里的index.mapping.coerce被設(shè)置為false):
curl -iXPUT 'localhost:9200/file?pretty' -H "Content-type: application/json" -d'
{
"settings": {
"number_of_shards":3,
"number_of_replicas":1,
"index.mapping.coerce": false
}
}
'
??使用如下命令修改file索引的映射:
curl -iXPUT 'localhost:9200/file/_mapping/object?pretty' -H "Content-type: application/json" -d'
{
"properties": {
"FileObject": {
"properties": {
"FileID": {
"type": "keyword",
"doc_values": false,
"ignore_above": 41
},
"InfoKind": {
"type": "integer",
"coerce": false
},
"Source": {
"type": "keyword",
"ignore_above": 2
},
"FileName": {
"type": "keyword",
"ignore_above": 256
},
"StoragePath": {
"type": "keyword",
"doc_values": false,
"ignore_above": 256
},
"FileHash": {
"type": "keyword",
"doc_values": false,
"ignore_above": 32
},
"FileFormat": {
"type": "keyword",
"ignore_above": 32
},
"Title": {
"type": "keyword",
"ignore_above": 128
},
"SecurityLevel": {
"type": "keyword",
"ignore_above": 1
},
"SubmiterName": {
"type": "keyword",
"ignore_above": 50
},
"SubmiterOrg": {
"type": "keyword",
"ignore_above": 100
},
"EntryTime": {
"type": "date",
"format": "yyyyMMddHHmmss"
},
"FileSize": {
"type": "integer",
"coerce": false
}
}
}
}
}
'
??使用如下命令查看file的映射信息:
curl -iXGET 'localhost:9200/file/_mapping?pretty'
??可以看到返回的映射信息:
{
"file" : {
"mappings" : {
"object" : {
"properties" : {
"FileObject" : {
"properties" : {
"EntryTime" : {
"type" : "date",
"format" : "yyyyMMddHHmmss"
},
"FileFormat" : {
"type" : "keyword",
"ignore_above" : 32
},
"FileHash" : {
"type" : "keyword",
"doc_values" : false,
"ignore_above" : 32
},
"FileID" : {
"type" : "keyword",
"doc_values" : false,
"ignore_above" : 41
},
"FileName" : {
"type" : "keyword",
"ignore_above" : 256
},
"FileSize" : {
"type" : "integer",
"coerce" : false
},
"InfoKind" : {
"type" : "integer",
"coerce" : false
},
"SecurityLevel" : {
"type" : "keyword",
"ignore_above" : 1
},
"Source" : {
"type" : "keyword",
"ignore_above" : 2
},
"StoragePath" : {
"type" : "keyword",
"doc_values" : false,
"ignore_above" : 256
},
"SubmiterName" : {
"type" : "keyword",
"ignore_above" : 50
},
"SubmiterOrg" : {
"type" : "keyword",
"ignore_above" : 100
},
"Title" : {
"type" : "keyword",
"ignore_above" : 128
}
}
}
}
}
}
}
}
??現(xiàn)在我們可以向file索引提交數(shù)據(jù)對(duì)象了,使用如下命令:
curl -iXPOST 'localhost:9200/file/object/31000000001190000138022019021416121100001?pretty' -H "Content-type: application/json" -d'
{
"FileObject": {
"FileID": "31000000001190000138022019021416121100001",
"InfoKind": 1,
"Source": "3",
"FileName": "tollgate_3_lane_4_20190214161211.jpg",
"StoragePath": "/tollgate/3/lane/4/images",
"FileHash": "38b8c2c1093dd0fec383a9d9ac940515",
"FileFormat": "Jpeg",
"Title": "tollgate_3_lane_4_20190214161211",
"SecurityLevel": "3",
"SubmiterName": "zhangkai",
"SubmiterOrg": "pudong",
"EntryTime": "20190214161214",
"FileSize": 94208
}
}
'
??視圖庫中對(duì)象的字段不用進(jìn)行全文檢索,也可以使用關(guān)系數(shù)據(jù)庫作為存儲(chǔ)容器,但需要對(duì)JSON數(shù)據(jù)進(jìn)行反序列化解析相應(yīng)字段入庫,查詢出庫時(shí)需要將多個(gè)字段序列化為JSON數(shù)據(jù)。固然在編程時(shí)可以使用ORM和JSON序列化中間件來完成工作,但在海量請(qǐng)求下,效率會(huì)有影響。使用ES可以利用ES的restful接口和JSON存儲(chǔ)格式的天然特性以契合規(guī)范要求。
??在視圖庫規(guī)范中有一些自定義的約束,這些涉及數(shù)據(jù)有效性檢驗(yàn)的服務(wù)應(yīng)該部署在ES入庫之前。在本實(shí)例中,更多的是把ES作為一個(gè)Nosql數(shù)據(jù)庫使用。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。