Elasticsearch索引與mapping映射


索引操作

創建索引

es創建索引的請求方式如下:

PUT /<index>
  • 請求的方法用PUT。
  • /后面直接跟索引的名稱即可。
  • 索引的設置和字段都放在Body中。

比如我們創建一個名字叫組織機構的索引,這個索引只有兩個字段,一個id,一個name。並且這個索引設置為2個分片,2個副本。

我們使用Postman發送請求,如下:

http://localhost:9200/orgnization

請求的方法選擇PUT。然后在請求體(Body)中,寫上索引的字段名稱,索引的分片數和副本數,如下:

{
    "settings":{
        "number_of_shards":2,
        "number_of_replicas":2
    },
    "mappings":{
        "properties":{
            "id":{
                "type":"long"
            },
            "name":{
                "type":"text"
            }
        }
    }
}

我們觀察一下,請求體中分為兩個部分:settings和mappings。在settings中,我們設置了分片數和副本數。

  • number_of_shards:分片的數量;
  • number_of_replicas:副本的數量;

在mappings中,我們設置索引的字段,在這里,我們只設置了id和name,id的映射類型是long,name的映射類型是text。

請求體寫完后,我們點擊發送,es返回的結果如下:

{
    "acknowledged": true,
    "shards_acknowledged": true,
    "index": "orgnization"
}

說明索引創建成功,索引的名字正是我們在請求中設置的orgnization。

然后,我們通過elasticsearch-head插件觀察一下剛才創建的索引

我們可以看到索引orgnization已經創建好了,它有2個分片,分別是0和1,並且每個分片都是兩個副本。如果我們仔細觀察這個圖,可以看出node-chun節點中的0分片,和node-yao節點中的1分片,它們的邊框是加粗的,這說明它們是主節點,而邊框沒有加粗的節點是從節點,也就是我們說的副本節點

查看索引

如果我們要查看一個索引的設置,可以通過如下請求方式: 

GET /<index>

在我們的例子中,查看orgnization索引的設置,我們在Postman中發送如下的請求:

{
    "orgnization": {
        "aliases": {},
        "mappings": {
            "properties": {
                "id": {
                    "type": "long"
                },
                "name": {
                    "type": "text"
                }
            }
        },
        "settings": {
            "index": {
                "routing": {
                    "allocation": {
                        "include": {
                            "_tier_preference": "data_content"
                        }
                    }
                },
                "number_of_shards": "2",
                "provided_name": "orgnization",
                "creation_date": "1636182188268",
                "number_of_replicas": "2",
                "uuid": "93U8-D3FSf2ZsVveV6uPUw",
                "version": {
                    "created": "7100299"
                }
            }
        }
    }
}

我們可以看到索引的具體設置,比如:mapping的設置,分片和副本的設置。這些和我們創建索引時候的設置是一樣的。

修改索引

索引一旦創建,我們是無法修改里邊的內容的,比如說修改索引字段的名稱。但是我們是可以向索引中添加其他字段的,添加字段的方式如下:

PUT /<index>/_mapping

然后在我們的請求體中,寫好新添加的字段。比如,在我們的例子當中,新添加一個type字段,它的類型我們定義為long,請求如下:

http://localhost:9200/orgnization/_mapping

請求類型要改為PUT,請求體如下:

{
  "properties": {
    "type": {
      "type": "long"
    }
  }
}

添加索引字段成功,我們再使用GET查看一下索引,如圖:

{
    "orgnization": {
        "aliases": {},
        "mappings": {
            "properties": {
                "id": {
                    "type": "long"
                },
                "name": {
                    "type": "text"
                },
                "type": {
                    "type": "long"
                }
            }
        },
        "settings": {
            "index": {
                "routing": {
                    "allocation": {
                        "include": {
                            "_tier_preference": "data_content"
                        }
                    }
                },
                "number_of_shards": "2",
                "provided_name": "orgnization",
                "creation_date": "1636182188268",
                "number_of_replicas": "2",
                "uuid": "93U8-D3FSf2ZsVveV6uPUw",
                "version": {
                    "created": "7100299"
                }
            }
        }
    }
}

我們可以成功的查詢到新添加的索引字段了。

刪除索引

如果我們要刪除一個索引,請求方式如下:

DELETE /<index>

假如我們要刪除剛才創建的orgnization索引,我們只要把請求的方法改成DELETE,然后訪問我們索引就可以

http://localhost:9200/orgnization

關閉索引

如果索引被關閉,那么關於這個索引的所有讀寫操作都會被阻斷。索引的關閉也很簡單,請求方式如下:

POST /<index>/_close

在我們的例子中,如果要關閉索引,將請求方法改成POST,然后發送如下請求:

http://localhost:9200/orgnization/_close

打開索引

與關閉索引相對應的是打開索引,請求方式如下:

POST /<index>/_open

在我們的例子中,如果要打開索引,將請求方法改成POST,然后發送如下請求:

http://localhost:9200/orgnization/_open

凍結索引

凍結索引和關閉索引類似,關閉索引是既不能讀,也不能寫。而凍結索引是可以讀,但是不能寫。凍結索引的請求方式如下:

POST /<index>/_freeze

對應我們的例子當中:

http://localhost:9200/orgnization/_freeze

解凍索引

與凍結索引對應的是解凍索引,方式如下:

POST /<index>/_unfreeze

對應我們的例子:

http://localhost:9200/orgnization/_unfreeze

Setting配置

setting為ES索引的配置屬性,索引的配置項按是否可以更改分靜態(static)屬性與動態配置。

靜態配置即索引創建后不能修改,靜態配置只能在創建索引時或者在狀態為 closed index的索引(閉合的索引)上設置。

索引靜態配置

index.number_of_shards 主分片數,默認為5。只能在創建索引時設置,不能修改。

index.shard.check_on_startup 是否在索引打開前檢查分片是否損壞,當檢查到分片損壞將禁止分片被打開。可選值:false:不檢測;checksum:只檢查物理結構;true:檢查物理和邏輯損壞,相對比較耗CPU;fix:類同與false,7.0版本后將廢棄。默認值:false。

index.codec 數據存儲的壓縮算法,默認算法為LZ4,也可以設置成best_compression,best_compression壓縮比較好,但存儲性能比LZ4差。

index.routing_partition_size 路由分區數,默認為 1,只能在索引創建時設置。此值必須小於index.number_of_shards,如果設置了該參數,如果設置了該參數,其路由算法為: (hash(_routing) + hash(_id) % index.routing_parttion_size ) % number_of_shards。如果該值不設置,則路由算法為 hash(_routing) % number_of_shardings,_routing默認值為_id。

索引動態配置

index.refresh_interval 執行刷新操作的頻率,這使得索引的最近更改可以被搜索。默認為 1s。可以設置為 -1 以禁用刷新。

index.max_result_window 用於索引搜索的 from+size 的最大值。默認為 10000。

index.max_docvalue_fields_search 一次查詢最多包含開啟doc_values字段的個數,默認為100。

index.number_of_replicas 每個主分片的副本數,默認為 1,該值必須大於等於0

index.auto_expand_replicas 基於可用節點的數量自動分配副本數量,默認為 false(即禁用此功能)

index.blocks.read_only 設置為 true 使索引和索引元數據為只讀,false 為允許寫入和元數據更改。

index.max_rescore_window 在搜索此索引中 rescore 的 window_size 最大值

index.blocks.read_only_allow_delete 與index.blocks.read_only基本類似,唯一的區別是允許刪除動作。

index.blocks.write 設置為 true 可禁用對索引的寫入操作。

index.blocks.read 設置為 true 可禁用對索引的讀取操作

index.blocks.metadata 設置為 true 可禁用索引元數據的讀取和寫入。

index.max_refresh_listeners 索引的每個分片上可用的最大刷新偵聽器數。

對於已存在的索引,我們想要修改它的動態配置,可以使用_settings方法。

PUT  /test_setting/_settings
{
    "number_of_replicas": "0"              
}

mapping配置

通常索引的 Mapping 結構可以在創建索引時由 ElasticSearch 幫我們自動構建,字段類型由 ElasticSearch 自動推斷,但這樣做有一些問題,比如字段類型推斷不准確,默認所有字段都會構建倒排索引等,自定義Mapping就可以解決上述這些問題。

我們創建了索引,在創建索引的時候,我們指定了mapping屬性,mapping屬性中規定索引中有哪些字段,字段的類型是什么。在mapping中,我們可以定義如下內容:

  • 類型為String的字段,將會被全文索引;
  • 其他的字段類型包括:數字、日期和geo(地理坐標);
  • 日期類型的格式;
  • 動態添加字段的映射規則;

字段的可用類型如下:

  • 簡單的類型,比如:text(分詞),keyword(不分詞),date,long,double,boolean,ip。我們可以看到,類型當中沒有String,字符串的類型是text,所有text類型的字段都會被全文索引。數字類型有兩個,long(長整型)和double(浮點型)。
  • JSON的層級類型:Object(對象)和Nested(數組對象)。Object類型時,該字段可以存儲一個JSON對象;Nested類型時,該字段可以存儲一個數組對象。
  • 復雜的類型:包括 geo_point、geo_shape和completion。

索引的創建需要配置mapping與setting兩部分。基本格式:

{
    "mappings":{
		"_all":{
			"enabled":false  #默認情況,ElasticSarch自動使用_all所有的文檔的域都會被加到_all中進行索引。可以使用"_all" : {"enabled":false} 開關禁用它。如果某個域不希望被加到_all中,可以使用"include_in_all":false關閉
		},
		"properties":{
			"uuid":{
				"type":"text",
				"copy_to":"_search_all", #對應_search_all字段,可以對其進行全文檢索
				"fields":{
					"keyword":{
						"type":"keyword",  
						"ignore_above":150  #ignore_above 默認值是256,當字段文本的長度大於指定值時,不做倒排索引。
					}
				}
			},
			"name":{
				"type":"text",
				"copy_to":"_search_all",
				"analyzer":"ik_max_word",  # ik_max_word 插件會最細粒度分詞
				"search_analyzer":"ik_smart",  # ik_smart 粗粒度分詞
				"fields":{
					"keyword":{
						"type":"keyword",
						"ignore_above":150
					}
				}
			},
			"dt_from_explode_time":{
				"type":"date",
				"copy_to":"_search_all",
				"format":"strict_date_optional_time||epoch_millis"
			},
			"_search_all":{
				"type":"text"
			}
		},
		"date_detection":false,  #關閉日期自動檢測,如果開啟,會對於設置為日期格式的字段進行判斷
		"dynamic_templates":[   #用於自定義在動態添加field的時候自動給field設置的數據類型
			{
				"strings":{
					"match_mapping_type":"string",
					"mapping":{
						"type":"text",
						"copy_to":"_search_all",
						"fields":{
							"keyword":{
								"type":"keyword",
								"ignore_above":150
							}
						}
					}
				}
			}
		]
        
    },
    "settings":{
        "index":{
            "number_of_shards":6, #分片數量
            "number_of_replicas":1  #副本數量
        }
    }
}

常用數據類型

text、keyword、number、array、range、boolean、date、geo_point、ip、nested、object。

  • text:默認會進行分詞,支持模糊查詢(5.x之后版本string類型已廢棄,請大家使用text)。 
  • keyword:不進行分詞,默認開啟doc_values來加速聚合排序操作,占用了大量磁盤io 如非必須可以禁用doc_values。
  • number:如果只有過濾場景 用不到range查詢的話,使用keyword性能更佳,另外數字類型的doc_values比字符串更容易壓縮。
  • range:對數據的范圍進行索引,目前支持 number range、date range 、ip range。
  • array:es不需要顯示定義數組類型,只需要在插入數據時用’[]‘表示即可。[]中的元素類型需保持一致。
  • boolean: 只接受true、false,也可以是字符串類型的“true”、“false”。
  • date:支持毫秒、根據指定的format解析對應的日期格式,內部以long類型存儲。
  • geo_point:存儲經緯度數據對。
  • ip:將ip數據存儲在這種數據類型中,方便后期對ip字段的模糊與范圍查詢。
  • ested:嵌套類型,一種特殊的object類型,存儲object數組,可檢索內部子項。
  • object:嵌套類型,不支持數組。
{
  "mappings": {
    "properties": {
      "price": {
        "type": "long"
      },
      "color": {
        "type": "keyword"
      },
      "brand": {
        "type": "keyword"
      },
      "sold_date": {
        "type": "date", // 使用date類型時要指定format,否則在使用range查詢+時間表達式now/d等時,會特別坑爹
        "format":"yyyyMMdd"
      }
    }
  }
}

其他參數:

"field": {  
	 "type":  "text", //文本類型  ,指定類型
   
	 "index": "false"// ,設置成false,字段將不會被索引  
	 
	 "analyzer":"ik"//指定分詞器  
	 
	 "boost":1.23//字段級別的分數加權  
	 
	 "doc_values":false//對not_analyzed字段,默認都是開啟,analyzed字段不能使用,對排序和聚合能提升較大性能,節約內存,如果您確定不需要對字段進行排序或聚合,或者從script訪問字段值,則可以禁用doc值以節省磁盤空間:
	 
	 "fielddata":{"loading" : "eager" }//Elasticsearch 加載內存 fielddata 的默認行為是 延遲 加載 。 當 Elasticsearch 第一次查詢某個字段時,它將會完整加載這個字段所有 Segment 中的倒排索引到內存中,以便於以后的查詢能夠獲取更好的性能。
	 
	 "fields":{"keyword": {"type": "keyword","ignore_above": 256}} //可以對一個字段提供多種索引模式,同一個字段的值,一個分詞,一個不分詞  
	 
	 "ignore_above":100 //超過100個字符的文本,將會被忽略,不被索引
	   
	 "include_in_all":ture//設置是否此字段包含在_all字段中,默認是true,除非index設置成no選項  
	 
	 "index_options":"docs"//4個可選參數docs(索引文檔號) ,freqs(文檔號+詞頻),positions(文檔號+詞頻+位置,通常用來距離查詢),offsets(文檔號+詞頻+位置+偏移量,通常被使用在高亮字段)分詞字段默認是position,其他的默認是docs  
	 
	 "norms":{"enable":true,"loading":"lazy"}//分詞字段默認配置,不分詞字段:默認{"enable":false},存儲長度因子和索引時boost,建議對需要參與評分字段使用 ,會額外增加內存消耗量  
	 
	 "null_value":"NULL"//設置一些缺失字段的初始化值,只有string可以使用,分詞字段的null值也會被分詞  
	 
	 "position_increament_gap":0//影響距離查詢或近似查詢,可以設置在多值字段的數據上火分詞字段上,查詢時可指定slop間隔,默認值是100  
	 
	 "store":false//是否單獨設置此字段的是否存儲而從_source字段中分離,默認是false,只能搜索,不能獲取值  
	 
	 "search_analyzer":"ik"//設置搜索時的分詞器,默認跟ananlyzer是一致的,比如index時用standard+ngram,搜索時用standard用來完成自動提示功能  
	 
	 "similarity":"BM25"//默認是TF/IDF算法,指定一個字段評分策略,僅僅對字符串型和分詞類型有效  
	 
	 "term_vector":"no"//默認不存儲向量信息,支持參數yes(term存儲),with_positions(term+位置),with_offsets(term+偏移量),with_positions_offsets(term+位置+偏移量) 對快速高亮fast vector highlighter能提升性能,但開啟又會加大索引體積,不適合大數據量用  
   }

常用的有: 

  • type:field的類型。
  • index:該field是否會被索引。
  • analyzer:指定的分詞器。
  • doc_values:開啟后對聚合入分組或排序有增益,默認開啟。

mapping之date date_nanos

JSON沒有date數據類型,但我們可以把以下類型的數據作為日期時間存入ES。

在ES的內部,這些數據都是按照毫秒數(長整型)存儲的,只是它們展現形式有如下多種。 

類型 說明
字符串 日期格式的字符串,如"2015-01-01"或"2015/01/01 12:10:30"
長整型 從開始紀元(1970-01-01 00:00:00 UTC)開始的毫秒數
整型 從開始紀元(1970-01-01 00:00:00 UTC)開始的秒數

上面的UTC(Universal Time Coordinated) 叫做世界統一時間,中國大陸和 UTC 的時差是 + 8 ,也就是 UTC+8。在ES內部,時間以毫秒數的UTC存儲。

1、日期格式

date的格式可以被指定的,如果沒有特殊指定,默認格式是"strict_date_optional_time||epoch_millis"

這段話可以理解為格式為strict_date_optional_time或者epoch_millis

(1)什么是epoch_millis?

epoch_millis就是從開始紀元(1970-01-01 00:00:00 UTC)開始的毫秒數-長整型。

如下圖,2020/8/31 14:57:56是我們常用的日期格式,它距離1970-01-01 00:00:00 有 1598857076000豪秒。所以可以用長整型1598857076000表示2020/8/31 14:57:56。

(2)什么是strict_date_optional_time?

strict_date_optional_time是date_optional_time的嚴格級別,這個嚴格指的是年份、月份、天必須分別以4位、2位、2位表示,不足兩位的話第一位需用0補齊。

常見的格式有如下:

  • yyyy
  • yyyyMM
  • yyyyMMdd
  • yyyyMMddHHmmss
  • yyyy-MM
  • yyyy-MM-dd
  • yyyy-MM-ddTHH:mm:ss
  • yyyy-MM-ddTHH:mm:ss.SSS
  • yyyy-MM-ddTHH:mm:ss.SSSZ

工作常見到是"yyyy-MM-dd HH:mm:ss",但是ES是不支持這格式的,需要在dd后面加個T,這個是固定格式。上面最后一個里大寫的"Z"表示時區。

你就是想用yyyy-MM-dd HH:mm:ss?

date類型,還支持一個參數format,它讓我們可以自己定制化日期格式。

比如format配置了“格式A||格式B||格式C”,插入一個值后,會從左往右匹配,直到有一個格式匹配上。

{
    "mappings":{
        "properties":{
            "birthday":{
                "type":"date",
                "format":"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
            }
        }
    }
}

(3)date_nanos類型,支持納秒

date類型支持到毫秒,如果特殊情況下用到納秒得用date_nanos這個類型。

為索引自定義Mapping

語法結構:

{
    "mappings": {
        "properties": {
            "age": {
                "type": "integer"
            },
            "email": {
                "type": "keyword"
            },
            "name": {
                "type": "text"
            }
        }
    }
}

PUT http://localhost:9200/users。請求的方法我們要使用PUT,路徑是我們的索引名稱,請求體當中是我們為索引添加的字段和字段的類型。

最佳實踐

我們可以完全參考手冊編寫 Mapping ,但不建議這樣做,容易出錯,調試也麻煩,可以通過創建一個測試索引並插入測試文檔,然后查看ElasticSearch為這個索引自動創建的Mapping,基於這個Mapping進行修改來構建我們自己的 Mapping。

在存在的映射中添加字段

正如上面所示,我們在一個索引中添加了字段,但是現在我們要補充額外的字段,這時,我們要怎么做呢?

PUT /users/_mapping
{
  "properties": {
    "employee-id": {
      "type": "keyword",
      "index": false
    }
  }
}

我們使用PUT方法,后面跟隨我們的索引名稱,再接上_mapping,請求體中是我們新添加的映射字段,我們指定了字段的類型為keyword,index索引為false,說明這個字段只用於存儲,不會用於搜索,搜索這個字段是搜索不到的。

我們在更新字段時候,是不能修改字段的類型的。如果我們要修改字段的類型,最好是新建一個新的字段,指定正確的類型,然后再更新索引,以后我們只需要查詢這個新增的字段就可以了。

查看索引中的字段映射

如果我們要查看已知索引的字段映射,可以向ES發送如下的請求:

GET /users/_mapping

請求的方法是GET,請求的路徑是我們索引的名稱my-index,再加上一個_mapping,得到的返回結果如下:

返回的結果中,我們可以看到索引的名稱users,還有我們添加的字段,也包括后續補充的employee-id字段。  

修改mapping中的字段類型

mapping中字段類型一旦設定后禁止直接修改。因為lucene實現的倒排索引生成后不允許修改,除非重建索引映射,然后做reindex操作。

以上面例子的索引orgnization為例。

(1)創建一個備份索引orgnization_bak

{
    "settings":{
        "number_of_shards":2,
        "number_of_replicas":2
    },
    "mappings":{
        "properties":{
            "id":{
                "type":"long"
            },
            "name":{
                "type":"text"
            }
        }
    }
}

(2) reindex操作 

POST http://localhost:9200/_reindex

請求體:

{
  "source": {"index":"舊索引"},
  "dest": {"index":"備份索引"}
}

其中舊索引就是orgnization,備份索引是orgnization_bak。

(3)刪除舊索引orgnization

(4)創建新索引orgnization,重新指定字段類型

{
    "settings":{
        "number_of_shards":2,
        "number_of_replicas":2
    },
    "mappings":{
        "properties":{
            "id":{
                "type":"long"
            },
            "name":{
                "type":"keyword"
            }
        }
    }
}

(5)再reindex操作 

POST http://localhost:9200/_reindex

請求體為:

{
  "source": {"index":"備份索引"},
  "dest": {"index":"新索引"}
}

此時的備份索引是orgnization_bak,新索引就是我們剛剛創建的orgnization。

注:在大數據量的情況,reindex操作不知道效率如何,慎用。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM