Mục lục- 1 Dynamic Mapping
- 1.1 Dynamic Mapping là gì
- 1.2 Thử nghiệm Dynamic Mapping
- 1.3 Phân tích nguyên nhân kết quả tìm kiếm không nhất quán
- 2 Kích hoạt chiến lược Dynamic Mapping
- 2.1 Ràng buộc chiến lược
- 2.2 Ví dụ về chiến lược
- 3 Tùy chỉnh chiến lược Dynamic Mapping
- 3.1 date_detection - Chiến lược nhận dạng ngày
- 3.2 Tùy chỉnh mẫu Dynamic Mapping trong type
- 3.3 [Đã lỗi thời] Tùy chỉnh mẫu mặc định trong index
- Tài liệu tham khảo
Lưu ý: Các ví dụ trong bài viết này sử dụng phiên bản Elasticsearch 6.6.0, các phiên bản khác có thể có sự khác biệt.
1 Dynamic Mapping
1.1 Dynamic Mapping là gì
Dynamic Mapping là một tính năng quan trọng của Elasticsearch: không cần phải tạo index trước, định nghĩa thông tin mapping và type, bạn có thể chèn trực tiếp dữ liệu tài liệu vào ES, và ES sẽ tự động cấu hình type và các thông tin mapping cho mỗi field mới dựa trên kiểu dữ liệu có thể có của nó, quá trình này được gọi là Dynamic Mapping.
Ví dụ về Dynamic Mapping trong Elasticsearch:
| Nội dung trường (field) | Kiểu trường được ánh xạ (type) |
|---|---|
| true | false | boolean |
| 1234 | long |
| 123.4 | float |
| 2018-10-10 | date |
| "hello world" | text |
Lưu ý: Mặc dù Dynamic Mapping tiện lợi, nhưng không trực quan. Để tùy chỉnh các cài đặt liên quan, bạn có thể tạo index và type trước khi thêm tài liệu, và cấu hình mapping tương ứng cho type, để thay thế cho Dynamic Mapping. Cấu hình mapping có thể tham khảo bài viết: ES 11 - Cách cấu hình Mapping trong Elasticsearch.
1.2 Thử nghiệm Dynamic Mapping
(1) Chèn dữ liệu sau:
Nếu đã có index website, hãy xóa
DELETE blogtrước, sau đó thực hiện các thao tác chèn dưới đây:
PUT blog/_doc/1
{
"blog_id": 10001,
"author_id": 5520,
"post_date": "2018-01-01",
"title": "bài blog đầu tiên của tôi",
"content": "bài blog đầu tiên trên website"
}
PUT blog/_doc/2
{
"blog_id": 10002,
"author_id": 5520,
"post_date": "2018-01-02",
"title": "bài blog thứ hai của tôi",
"content": "bài blog thứ hai trên website"
}
PUT blog/_doc/3
{
"blog_id": 10003,
"author_id": 5520,
"post_date": "2018-01-03",
"title": "bài blog thứ ba của tôi",
"content": "bài blog thứ ba trên website"
}
(2) Thực hiện các bài kiểm tra tìm kiếm:
Lưu ý: Trường hợp có 3 kết quả.
GET blog/_search?q=2018 // 1 kết quả, các phiên bản trước 5.6 là 3 kết quả
GET blog/_search?q=2018-01-01 // 1 kết quả, các phiên bản trước 5.6 là 3 kết quả
GET blog/_search?q=post_date:2018 // 1 kết quả
GET blog/_search?q=post_date:2018-01-01 // 1 kết quả
(3) Xem mapping được tự động tạo bởi ES:
GET blog/_mapping
// Kết quả như sau:
{
"blog" : { // index là blog
"mappings" : {
"_doc" : { // type là _doc - để dễ dàng nâng cấp phiên bản sau này
"properties" : {
"author_id" : {
"type" : "long"
},
"blog_id" : {
"type" : "long"
},
"content" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"post_date" : {
"type" : "date" // Ngày "2018-01-01" được tự động nhận dạng là kiểu date
},
"title" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
}
}
}
}
1.3 Phân tích nguyên nhân kết quả tìm kiếm không nhất quán
Nếu bạn đang sử dụng phiên bản Elasticsearch 5.6.x trở về trước, kết quả tìm kiếm trong mục [1.2] sẽ không nhất quán, lý do là:
Khi Elasticsearch tự động tạo mapping, nó ánh xạ các field khác nhau với các kiểu dữ liệu khác nhau, và các kiểu dữ liệu khác nhau có hành vi phân tích, tìm kiếm khác nhau.
Khi chúng ta tìm kiếm bằng cách
q=xxx, tầng dưới sẽ tìm kiếm từ trường_allcủa mỗi tài liệu —— Elasticsearch mặc định trích xuất tất cả các giá trị của các field trong tài liệu vào một trường meta có tên_all.Tài liệu chính thức chỉ ra rằng, từ phiên bản 6.0+, trường
_allđã bị cấm sử dụng, và chúng ta nên sử dụngcopy_tođể thực hiện chức năng tương tự.—— Điều này có nghĩa là, nếu trường_allbị tắt, sẽ không có hiện tượng kết quả tìm kiếm không nhất quán.
(1) GET website/blog/_search?q=2018
Giá trị của
_alltrong tài liệu id=1 là:2018-01-01 my first blog my first blog in the website 5520Giải thích: Trường
_allchỉ mục tất cả các giá trị dưới dạng chuỗi, vì vậy ngày tháng được chỉ mục thành ba giá trị: năm, tháng, ngày. Kết quả chỉ mục ngược của trường_allnhư sau:| | doc1 | doc2 | Doc3 | |---|---|---|---| | 2018 | \* | \* | \* | | 01 | \* | \* | \* | | 02 | | \* | | | 03 | | | \* |
Trong tìm kiếm này, Elasticsearch tìm kiếm từ trường
_all, và cả 3 tài liệu đều có2018, vì vậy có 3 kết quả.
(2) GET website/blog/?q=2018-01-01
Tương tự như (1), Elasticsearch cũng tìm kiếm từ trường
_all, và số kết quả cũng là 3.
(3) GET website/blog/_search?q=post_date:2018-01-01
Tìm kiếm này chỉ định điều kiện tìm kiếm, Elasticsearch sẽ tìm kiếm từ trường post_date, và post_date được ánh xạ thành kiểu date, vì vậy sẽ thực hiện so khớp chính xác.
Trường kiểu date có định dạng chỉ mục mặc định cố định. Kết quả chỉ mục ngược của trường
post_datenhư sau:| | doc1 | doc2 | doc3 | |---|---|---|---| | 2018-01-01 00:00:00 UTC | \* | | | | 2018-01-02 00:00:00 UTC | | \* | | | 2018-01-03 00:00:00 UTC | | | \* |
Có thể thấy, chỉ có 1 kết quả thỏa mãn, đó là doc1.
(4) GET /_search?q=post_date:2018
Đây là một tối ưu hóa trong phiên bản ES 5.x, tìm kiếm
post_date:01sẽ không có kết quả, tìm kiếm 2018 sẽ cho ra kết quả đầu tiên.
2 Kích hoạt chiến lược Dynamic Mapping
2.1 Ràng buộc chiến lược
| Chiến lược | Chức năng |
|---|---|
true |
Kích hoạt —— Khi gặp trường không quen thuộc, thực hiện Dynamic Mapping |
false |
Tắt —— Bỏ qua các trường không quen thuộc |
strict |
Khi gặp trường không quen thuộc, báo lỗi |
2.2 Ví dụ về chiến lược
(1) Sử dụng các chiến lược ràng buộc khác nhau:
PUT blog_user
{
"mappings": {
"_doc": {
"dynamic": "strict", // Chiến lược kiểm soát nghiêm ngặt
"properties": {
"name": { "type": "text" },
"address": {
"type": "object",
"dynamic": "true" // Kích hoạt chiến lược Dynamic Mapping
}
}
}
}
}
(2) Chèn dữ liệu để minh họa:
// Khi chèn dữ liệu, thêm một trường bổ sung
PUT blog_user/1
{
"name": "shou feng",
"content": "đây là blog của tôi", // Trường bổ sung
"address": {
"province": "guangdong",
"city": "guangzhou"
}
}
Sẽ ném ra lỗi sau:
{
"error": {
"root_cause": [
{
"type": "strict_dynamic_mapping_exception",
// Lỗi: Không cho phép thêm trường động
"reason": "mapping set to strict, dynamic introduction of [content] within [_doc] is not allowed"
}
],
"type": "strict_dynamic_mapping_exception",
"reason": "mapping set to strict, dynamic introduction of [content] within [_doc] is not allowed"
},
"status": 400
}
Thêm dữ liệu phù hợp với ràng buộc, thao tác sẽ thành công:
PUT blog_user/_doc/1
{
"name": "shou feng",
"address": {
"province": "guangdong",
"city": "guangzhou"
}
}
(3) Xem thông tin mapping:
GET user/_mapping
// Thông tin mapping như sau:
{
"blog_user" : {
"mappings" : {
"_doc" : {
"dynamic" : "strict", // Ràng buộc nghiêm ngặt
"properties" : {
"address" : {
"dynamic" : "true", // Kích hoạt chiến lược Dynamic Mapping
"properties" : {
"city" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"province" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
},
"name" : {
"type" : "text"
}
}
}
}
}
}
3 Tùy chỉnh chiến lược Dynamic Mapping
3.1 date_detection - Chiến lược nhận dạng ngày
Đối với dữ liệu kiểu date, Elasticsearch có chiến lược nhận dạng mặc định, ví dụ "yyyy-MM-dd". Có trường hợp:
① Khi thêm tài liệu lần đầu, một field có giá trị như "2018-01-01", kiểu của nó sẽ được ánh xạ động thành date;
② Khi thêm tài liệu sau này, field đó có giá trị như "hello world", ES sẽ báo lỗi do không khớp kiểu.
Để giải quyết vấn đề này, bạn có thể tắt thủ công date_detection cho một type; nếu không cần tắt, nên chỉ định thủ công field này là kiểu date. Ví dụ:
PUT blog_user/_mapping/_doc
{
"date_detection": false
}
3.2 Tùy chỉnh mẫu Dynamic Mapping trong type
(1) Định nghĩa mẫu Dynamic Mapping trong type —— Ánh xạ tất cả các kiểu String thành kiểu text và keyword:
Xóa index
blog_userđã có:DELETE blog_user, sau đó thực hiện lệnh dưới đây:
PUT blog_user
{
"mappings": {
"_doc": {
"dynamic_templates": [
{
"en": { // Tên mẫu động
"match": "*_en", // Khớp với field có tên "*_en"
"match_mapping_type": "string",
"mapping": {
"type": "text", // Ánh xạ tất cả các kiểu string thành kiểu text
"analyzer": "english", // Sử dụng bộ phân tích từ english
"fields": {
"raw": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
]
}
}
}
(2) Thêm dữ liệu:
PUT blog_user/_doc/1
{
"name": "người dùng đăng ký đầu tiên"
}
PUT blog_user/_doc/2
{
"name_en": "người dùng đăng ký thứ hai"
}
(3) Tìm kiếm dữ liệu:
// Có kết quả: "name" không khớp với bất kỳ mẫu động nào, sử dụng bộ phân tích standard mặc định
GET blog_user/_search
{
"query": {
"match": {"name": "người"}
}
}
// Không có kết quả: "name_en" khớp với mẫu động, sử dụng bộ phân tích english, "the" là từ dừng và bị lọc bỏ
GET blog_user/_search
{
"query": {
"match": {"name_en": "người"}
}
}
Giải thích:
match_mapping_typehỗ trợ các kiểu[object, string, long, double, boolean, date, binary], nếu sử dụngtextsẽ ném ra lỗi sau:{ "error": { "root_cause": [ { "type": "mapper_parsing_exception", "reason": "Failed to parse mapping [_doc]: No field type matched on [text], possible values are [object, string, long, double, boolean, date, binary]" } ], "type": "mapper_parsing_exception", "reason": "Failed to parse mapping [_doc]: No field type matched on [text], possible values are [object, string, long, double, boolean, date, binary]", "caused_by": { "type": "illegal_argument_exception", "reason": "No field type matched on [text], possible values are [object, string, long, double, boolean, date, binary]" } }, "status": 400 }Trong các phiên bản trước 6.0, sẽ có cảnh báo lỗi thời sau:
Deprecation: match_mapping_type [text] is invalid and will be ignored: No field type matched on [text], possible values are [object, string, long, double, boolean, date, binary]
3.3 [Đã lỗi thời] Tùy chỉnh mẫu mặc định trong index
_default mapping - Mẫu ánh xạ mặc định giống như một biến toàn cục, có tác dụng cho index được cấu hình.
Mẫu ánh xạ mặc định không còn được hỗ trợ trong Elasticsearch 6.x, vì từ phiên bản 6.0, mỗi index chỉ có thể có một type, vì vậy mẫu mặc định không còn ý nghĩa.
Quá trình minh họa dưới đây được thực hiện trên các phiên bản trước 6.0.
(1) Định nghĩa mẫu ánh xạ mặc định trong index:
Xóa index
blog_userđã có:DELETE blog_user, sau đó thực hiện lệnh dưới đây:
PUT blog_user
{
"mappings": {
"_default_": {
"_all": { "enabled": false }
},
"_doc": {
"_all": { "enabled": true }
}
}
}
(2) Dynamic Mapping có thể kết hợp với Index Templates.
Cả việc tạo Index tự động và tạo Index một cách rõ ràng, Index Templates đều có thể được sử dụng để cấu hình mappings (ánh xạ), settings (cài đặt) và aliases (bí danh) mặc định cho index mới. Cách sử dụng cụ thể xin tham khảo blog: ES 10 - Cách sử dụng Index Templates trong Elasticsearch
Tài liệu tham khảo
(phiên bản 6.6) Tài liệu chính thức - Dynamic Mapping