ElasticSearch之数据建模

这篇具有很好参考价值的文章主要介绍了ElasticSearch之数据建模。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

写在前面

本文看下es数据建模相关的内容。

1:什么是数据建模

数据建模是对真实数据的一种抽象,最终映射为计算机形式的表现。其包括如下三个阶段:

1:概念模型
2:逻辑模型
3:数据模型

2:es数据建模的过程

es的数据建模其实就是确定各个字段都需要如何进行设置,什么类型?是否需要搜索?等,具体需要考虑的问题如下:
图像 es数据库 建模,ElasticSearch,elasticsearch,es数据建模

注意以上四个要素没有先后的顺序,而只是需要综合考虑的因素。

2.1:数据类型

为了选择合适的数据类型,我们来看下每种数据类型的特点。

2.1.1:text

默认会被分词器分词,可以搜索,但是不支持聚合和排序,如果想要支持的话需要显式将fielddata设置为true。

2.1.2:keyword

不会被分词,所以一般用在不需要分词时使用,如主键id,邮箱,手机号,身份证号等。支持聚合,搜索和排序,以及用于查询时精确匹配方式的过滤。

2.1.3:多字段类型

当希望一个数据按照多种的数据类型来存储,从而满足诸如按照不同的分词器进行分词,按照不同的查询条件进行查询(如存储为int则可以按照range来查询),但又不希望设置多个字段时使用。默认的在es中如果时字段时text类型的,则会默认添加一个名称为keyword的keyword类型的字段,当然实际工作中我们我们不需要这个默认行为则可以通过显式mapping来自己定义。

2.1.4:数值类型

数值类型是一种结构化数据,数值类型应该尽量设置能够满足存储要求的最小类型,如可以设置为byte,就不要设置为long。

2.1.5:枚举类型

枚举类型是一种结构化数据,建议设置为keyword,以获得更好的性能。

2.1.6:日期,布尔,地理信息等

设置为对应的类型即可。

2.2:搜索,聚合,排序

  • 搜索
    是否需要被搜索,也是对字段进行建模时要考虑的一个重要因素,因为搜索功能需要分词,以及创建对应的倒排索引数据结构,所以需要额外的存储消耗,以及构建对应数据结构的性能消耗。
  • 聚合,排序
    聚合和排序功能需要依赖于doc_values,和fielddata,需要简历对应的数据结构来满足聚合和排序功能,因此也会有对应的存储成本,和对应数据结构的维护成本。
    对于这三个因素可从以下方面进行考虑:
1:如果是同时不需要搜索,聚合和排序,则可考虑设置enable=false,不存储_source(还需要注意不存储_source的话将无法reindex和更新)
2:如果是不需要搜索,则可以设置index:false
3:如果不需要聚合和排序,则可以设置doc_values和fielddata为false
4:如果是更新频繁,聚合频繁,则可考虑设置keyword类型的eager_global_ordinals为true,可以利用缓存来提高性能。

2.3:额外存储字段值

如果希望额外存储字段值,则可以设置store:true,一般结合enbled:false使用。

enabled:false一般应用在一些指标数据的存储上,这些数据不需要reindex,更新。此时如果还希望查看某些字段的话则可以设置store为true。

但是实际的应用中不建议直接设置enabled:false,而是考虑使用高压缩的存储方式来减少存储的开销。

2.4:数据建模优化实例

假定我们要对如下的数据进行建模:
图像 es数据库 建模,ElasticSearch,elasticsearch,es数据建模
如下是默认生成的mapping:
图像 es数据库 建模,ElasticSearch,elasticsearch,es数据建模
其中cover_url被自动映射为text类型,并增加keyword类型的子字段,如下:

# Index 一本书的信息
PUT books/_doc/1
{
  "title": "Mastering ElasticSearch 5.0",
  "description": "Master the searching, indexing, and aggregation features in ElasticSearch Improve users’ search experience with Elasticsearch’s functionalities and develop your own Elasticsearch plugins",
  "author": "Bharvi Dixit",
  "public_date": "2017",
  "cover_url": "https://images-na.ssl-images-amazon.com/images/I/51OeaMFxcML.jpg"
}

#查询自动创建的Mapping
GET books/_mapping

图像 es数据库 建模,ElasticSearch,elasticsearch,es数据建模
假定根据实际的业务需求,cover url不需要支持搜索,只需要支持聚合即可,此时我们就可以将其显式的设置为keyword,并将index设置为false,如下:

DELETE books

#优化字段类型
PUT books
{
  "mappings": {
    "properties": {
      "author": {
        "type": "keyword"
      },
      "cover_url": {
        "type": "keyword",
        "index": false
      },
      "description": {
        "type": "text"
      },
      "public_date": {
        "type": "date"
      },
      "title": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 100
          }
        }
      }
    }
  }
}

GET books/_mapping

图像 es数据库 建模,ElasticSearch,elasticsearch,es数据建模
此时cover_url因为设置了index:false就不支持搜索了:

#Cover URL index 设置成false,无法对该字段进行搜索
POST books/_search
{
  "query": {
    "term": {
      "cover_url": {
        "value": "https://images-na.ssl-images-amazon.com/images/I/51OeaMFxcML.jpg"
      }
    }
  }
}

图像 es数据库 建模,ElasticSearch,elasticsearch,es数据建模
但依然是支持聚合的:

#Cover URL index 设置成false,依然支持聚合分析
POST books/_search
{
  "aggs": {
    "cover": {
      "terms": {
        "field": "cover_url",
        "size": 10
      }
    }
  }
}

图像 es数据库 建模,ElasticSearch,elasticsearch,es数据建模
假定需求发生变更,要求将文章的内容存储在content字段中,并且不需要做更新和reindex。

考虑到content内容比较大,所以如果放在_source中返回的话会占用比较多的网络带宽资源,并且数据查询到额速度也会降低,所以为了解决这个问题,我们可以考虑如下的两种方案:

1:source filtering不返回数据,特别是content
2:设置enabled:false,并设置字段store:true

其中对于1:source_fitering 只是在返回给客户端时不返回,在汇总数据时还是返回的,如下图:
图像 es数据库 建模,ElasticSearch,elasticsearch,es数据建模
所以对于这个需求我们需要通过2设置enabled:false来解决。

如下在mapping中显式设置enabled:false:

DELETE books
#新增 Content字段。数据量很大。选择将Source 关闭
PUT books
{
  "mappings": {
    "_source": {
      "enabled": false
    },
    "properties": {
      "author": {
        "type": "keyword",
        "store": true
      },
      "cover_url": {
        "type": "keyword",
        "index": false,
        "store": true
      },
      "description": {
        "type": "text",
        "store": true
      },
      "content": {
        "type": "text",
        "store": true
      },
      "public_date": {
        "type": "date",
        "store": true
      },
      "title": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 100
          }
        },
        "store": true
      }
    }
  }
}

图像 es数据库 建模,ElasticSearch,elasticsearch,es数据建模
插入数据:

# Index 一本书的信息,包含Content
PUT books/_doc/1
{
  "title": "Mastering ElasticSearch 5.0",
  "description": "Master the searching, indexing, and aggregation features in ElasticSearch Improve users’ search experience with Elasticsearch’s functionalities and develop your own Elasticsearch plugins",
  "content": "The content of the book......Indexing data, aggregation, searching.    something else. something in the way............",
  "author": "Bharvi Dixit",
  "public_date": "2017",
  "cover_url": "https://images-na.ssl-images-amazon.com/images/I/51OeaMFxcML.jpg"
}

#查询结果中,Source不包含数据
POST books/_search
{}

图像 es数据库 建模,ElasticSearch,elasticsearch,es数据建模
但依然可以查询和高亮,因为store:true所以会存储字段的原始值(但是enabled:false所以原始文档是不存储的,即_source是没有信息的)

#搜索,通过store 字段显示数据,同时高亮显示 conent的内容
POST books/_search
{
  "stored_fields": [
    "title",
    "author",
    "public_date"
  ],
  "query": {
    "match": {
      "content": "searching"
    }
  },
  "highlight": {
    "fields": {
      "content": {}
    }
  }
}

图像 es数据库 建模,ElasticSearch,elasticsearch,es数据建模

3:数据建模最佳实践

3.1:最佳实践一,如何处理关联关系

比如一个学生选择了多门课程,如果是在mysql等关系型数据库中就是1:n的关联关系。

按照如下的情况考虑:

1:如果是不需要通过关联的信息进行查询则优先考虑反范式化设计的存储方式,即存储到一个文档中
	问题:如果是查询的话,会存在查询不准的问题,此时需要考虑其他方式
2:如果是对关联关系需要精确查询的话,则考虑使用nest存储方式。
	问题:更新关联关系的数据都要更新整个文档,更新效率低
3:如果是需要更新的话,则考虑使用child/parent
  需要额外的维护关联关系,读取的性能比较差

需要注意:kibana目前不支持针对nest,child/parent数据的报表展示。如果希望使用kibana进行报表展示的话需要做出取舍。

3.2:最佳实践二,避免过多字段

出现字段过多的情况一般都是因为将dynamic mapping的值设置为true了。此时每次文档中有新增字段都会在mapping中增加字段信息。如果是mapping信息中字段过多的话会导致如下的问题:

1:mapping庞大,字段多,不好维护
2:mapping信息需要维护在cluster state中,而cluster state需要同步到所有节点中,所以集群压力会变大

因此我可以考虑将dynamic mapping设置为stric来避免这个问题,但这就要求我们在建模阶段就考虑清楚都需要那些字段,避免后期引起不必要的麻烦。除了设置dynamic mapping为strict外,还可以考虑通过设置index.mapping.total_fields.limits来限制字段最大个数,默认为1000。

dynamic还有另外两个值,false,此时文档会写入_source,但不索引,生成mapping。strict,此时写入报错,生产上建议设置为strict。

针对这种情况,来看个例子,首先来创建一个文档:

DELETE cookie_service

PUT cookie_service/_doc/1
{
 "url":"www.google.com",
 "cookies":{
   "username":"tom",
   "age":32
 }
}

查看mapping:
图像 es数据库 建模,ElasticSearch,elasticsearch,es数据建模
再来创建一个文档:

PUT cookie_service/_doc/2
{
 "url":"www.amazon.com",
 "cookies":{
   "login":"2019-01-01",
   "email":"xyz@abc.com"
 }
}

再来看mapping:
图像 es数据库 建模,ElasticSearch,elasticsearch,es数据建模
那么,如果实际场景中就是可能有多种不同的值该怎么办呢?可以考虑使用类似于竖表 的方式来处理这种属性不确定的情况。
首先定义mapping:

DELETE cookie_service
#使用 Nested 对象,增加key/value
PUT cookie_service
{
  "mappings": {
    "properties": {
      "cookies": {
        "type": "nested",
        "properties": {
          "name": {
            "type": "keyword"
          },
          "dateValue": {
            "type": "date"
          },
          "keywordValue": {
            "type": "keyword"
          },
          "IntValue": {
            "type": "integer"
          }
        }
      },
      "url": {
        "type": "keyword"
      }
    }
  }
}

其中name存储属性的名称,具体的值存储到对应类型的字段上去,比如date类型则存储到dateValue字段中,int类型的属性值则存储到intValue字段中。
图像 es数据库 建模,ElasticSearch,elasticsearch,es数据建模
我们来索引几个文档:

##写入数据,使用key和合适类型的value字段
PUT cookie_service/_doc/1
{
  "url": "www.google.com",
  "cookies": [
    {
      "name": "username",
      "keywordValue": "tom"
    },
    {
      "name": "age",
      "intValue": 32
    }
  ]
}


PUT cookie_service/_doc/2
{
  "url": "www.amazon.com",
  "cookies": [
    {
      "name": "login",
      "dateValue": "2019-01-01"
    },
    {
      "name": "email",
      "IntValue": 32
    }
  ]
}

接着查看数据:
图像 es数据库 建模,ElasticSearch,elasticsearch,es数据建模
可以正常查询,并且此时mapping信息也不会有任何的改变。

3.3:最佳实践三,避免正则查询

正则查询可能会引起性能问题,在生产环境中要避免。一般使用空间换时间的方案来解决,来看一个实际的例子。

比如现在有es的版本号信息存储在字段verison中,如7.1.0,现在要查询小版本号为1的所有文档,则可能使用如下的查询:

POST /esinfo/_search
{
  "query": {
    "regexp": {
      "name": "*.1.*"
    }
  }
}

那么,通过空间换时间的思想该如何解决这个问题呢?可以将主版本号,小版本号,bug修复版本号作为子字段的形式分为3个字段来存储,如下:

DELETE softwares
# 优化,使用inner object
PUT softwares/
{
  "mappings": {
    "_meta": {
      "software_version_mapping": "1.1"
    },
    "properties": {
      "version": {
        "properties": {
          "display_name": {
            "type": "keyword"
          },
          "hot_fix": {
            "type": "byte"
          },
          "marjor": {
            "type": "byte"
          },
          "minor": {
            "type": "byte"
          }
        }
      }
    }
  }
}

模拟索引一个文档:

#通过 Inner Object 写入多个文档
PUT softwares/_doc/1
{
  "version":{
  "display_name":"7.1.0",
  "marjor":7,
  "minor":1,
  "hot_fix":0  
  }

}

PUT softwares/_doc/2
{
  "version":{
  "display_name":"7.2.0",
  "marjor":7,
  "minor":2,
  "hot_fix":0  
  }
}

查询:

# 通过 bool 查询,
POST softwares/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "match": {
            "version.marjor": 7
          }
        },
        {
          "match": {
            "version.minor": 2
          }
        }
      ]
    }
  }
}

图像 es数据库 建模,ElasticSearch,elasticsearch,es数据建模

以上使用了filter查询,可以有效的利用到缓存,提高查询效率。

3.4:最佳实践四,避免空值聚合不准问题

如果是值为null,可能会会导致聚合不准的问题,如下:
图像 es数据库 建模,ElasticSearch,elasticsearch,es数据建模
结果为5,很明显是错误的。

可以通过设置null_value来解决这个问题:

DELETE ratings
PUT ratings
{
  "mappings": {
      "properties": {
        "rating": {
          "type": "float",
          "null_value": 1.0
        }
      }
    }
}


PUT ratings/_doc/1
{
 "rating":5
}
PUT ratings/_doc/2
{
 "rating":null
}


POST ratings/_search
{
  "size": 0,
  "aggs": {
    "avg": {
      "avg": {
        "field": "rating"
      }
    }
  }
}

图像 es数据库 建模,ElasticSearch,elasticsearch,es数据建模
此时结果为3,就符合业务上的要求了。

写在后面

参考文章列表

source filtering 。文章来源地址https://www.toymoban.com/news/detail-850915.html

到了这里,关于ElasticSearch之数据建模的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • ​ES elasticsearch-analysis-dynamic-synonym​连接数据库动态更新synonym近义词

            在很多搜索场景中,我们希望能够搜索出搜索词相关的目标,同时也希望能搜索出其近义词相关的目标。例如在商品搜索中,搜索“ 瓠瓜 ”,也希望能够搜索出“ 西葫芦 ”,但“ 西葫芦 ”商品名称因不含有“ 瓠瓜 ”,导致无法搜索出来。         此时就

    2024年02月09日
    浏览(43)
  • Java SpringBoot API 实现ES(Elasticsearch)搜索引擎的一系列操作(超详细)(模拟数据库操作)

    小编使用的是elasticsearch-7.3.2 基础说明: 启动:进入elasticsearch-7.3.2/bin目录,双击elasticsearch.bat进行启动,当出现一下界面说明,启动成功。也可以访问http://localhost:9200/ 启动ES管理:进入elasticsearch-head-master文件夹,然后进入cmd命令界面,输入npm run start 即可启动。访问http

    2024年02月04日
    浏览(54)
  • 十万字图文详解mysql、redis、kafka、elasticsearch(ES)多源异构不同种类数据库集成、数据共享、数据同步、不同中间件技术实现与方案,如何构建数据仓库、数据湖、数仓一体化?

    数据库大数据量、高并发、高可用解决方案,十万字图文详解mysql、redis、kafka、elasticsearch(ES)多源异构不同种类数据库集成、数据共享、数据同步、不同中间件技术实现与方案,如何构建数据仓库、数据湖、数仓一体化?Delta Lake、Apache Hudi和Apache Iceberg数仓一体化技术架构

    2024年02月07日
    浏览(51)
  • 【ES笔记02】ElasticSearch数据库之查询操作(match、must、must_not、should、_source、filter、range、exists、ids、term、terms)

    这篇文章,主要介绍ElasticSearch数据库之查询操作(match、must、must_not、should、_source、filter、range、exists、ids、term、terms)。 目录 一、布尔查询 1.1、主键查询 1.2、两种查询方式 (1)路径参数查询 (2)请求体参数查询 1.3、match查询 (1)match (2)match_all 1.4、过滤字段 1.5、布

    2023年04月09日
    浏览(52)
  • Elasticsearch实战(二十四)---ES数据建模一对多模型Nested结构

    我们如何把Mysql的模型合理的在ES中去实现? 就需要你对要存储的数据足够的了解,及对应用场景足够的深入分析,才能建立一个合适的模型,便于你后期扩展 一对一 模型 一对多 模型 多对多 模型 上一篇,我们介绍了 一对多模型,采用Object对象存储的巨大缺陷,本篇文章,我们

    2024年02月14日
    浏览(46)
  • Elasticsearch实战(二十三)---ES数据建模与Mysql对比 一对多模型

    我们如何把Mysql的模型合理的在ES中去实现? 就需要你对要存储的数据足够的了解,及对应用场景足够的深入分析,才能建立一个合适的模型,便于你后期扩展 一对一 模型 一对多 模型 多对多 模型 1.一对多 模型 我们现在有两个模型, 一个商品Product, 一个分类Category , 我们对比下一

    2024年02月08日
    浏览(56)
  • Elasticsearch实战(二十二)---ES数据建模与Mysql对比 一对一模型

    我们如何把Mysql的模型合理的在ES中去实现? 就需要你对要存储的数据足够的了解,及对应用场景足够的深入分析,才能建立一个合适的模型,便于你后期扩展 实体之间的关系: 一对一 模型 一对一(1:1):一个实体最多只能能另一个实体相关联,另一个实体如是。 例:一个只能

    2024年02月10日
    浏览(56)
  • Elasticsearch 对比传统数据库:深入挖掘 Elasticsearch 的优势

    当你为项目选择数据库或搜索引擎时,了解每个选项的细微差别至关重要。 今天,我们将深入探讨 Elasticsearch 的优势,并探讨它与传统 SQL 和 NoSQL 数据库的比较。 Elasticsearch 以强大的 Apache Lucene 库为基础,是一个分布式搜索和分析引擎。 它以其速度、可扩展性以及快速索引

    2024年02月10日
    浏览(44)
  • elasticsearch 数据库扩容

    遇见的问题: Failed to execute phase [query], all shards failed; shardFailures {[eo918sbJQ8-luXJZR5LyVQ] [todayonduty][0]: RemoteTransportException[[node-1][192.168.10.113:9300] [indices:data/read/search[phase/query]]]; nested: IllegalArgumentException[Inner result window is too large, the inner hit definition\\\'s [null]\\\'s from + size must be less than o

    2023年04月08日
    浏览(39)
  • Elasticsearch数据库

    Elasticsearch和MongoDB/Redis/Memcache一样,是非关系型数据库。是一个接近实时的搜索平台,从索引这个文档到这个文档能够被搜索到只有一个轻微的延迟,企业应用定位:采用Restful API标准的可扩展和高可用的实时数据分析的全文搜索工具。 可拓展:支持一主多从且扩容简易,只

    2024年02月04日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包