elasticsearch如何存储关联关系?

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 1. 前言 之所以写这篇文章是因为我已经在不止一个群里,看到有人问如何在ES中存储关联关系。 2. 答案 你可能会在网上看到有说Join datatype和Nested data type的,但是其实这都不是ES该有的玩法。 Join datatype和Nested data type都会涉及多次查询的开销 Join datatype本身的数据就是在不同的表中,对于分布式数据库,还涉及数据从不同的节点上拉取和组装的开销。 那么应该怎么做?答案就是用冗余的宽表来存储关联关系 举例说明 假如我需要在ES中存储的实体有书籍、书籍有作者信息、书名等等信息,显然实体之间有如下关系 如果在传统的关系型数据库中,就需要创建2张表,一张表表示作者,一张表代表书。但是对于nosql数据库,只需要一张表(书)即可,doc结构形如: { "name":"zhangsan", "publisher_identifier": "xxx-xxxx-xxx" "author":{ "name": "jobs", "phone": "111111111" } } 作者信息作为书的属性存储在一起,放一个doc中即可。 这样的做法必然是会带来数据冗余,但是以空间换时间,查询速度就有了保障。 现代的nosql数据库大多应对的海量数据的存储查询的问题,因此大都是分布式结构。在这种情况下,整体的设计方案必须足够简单,才能够易于维护和扩展。同样的做法,也完全适用于HBase。 3. 说几句某些人可能不爱听的话 ES集群的使用成本其实是很贵的,用了就别怕贵,觉得烧钱就别用 ES自身的性能优化工作做得还是很好的,对大多数人而言,不需要考虑优化,性能不够,就老老实实的加硬件就行。高版本相比低版本性能和稳定性都有很大的提升,优先考虑高版本 SSD对ES的性能提升非常明显(便宜不一定不是好货,但好货一定不便宜) 4. 参考资料 1.Join datatype 2.Nested data type 3.宽表和窄表的区别 打赏我

July 2, 2020 · 1 min

聊聊GeoHash

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 本文基于 Redis 3.2.0 前言 鲁班门前弄大斧,笔者今天要聊一下geohash。 redis/elasticsearch/mongoDB 中地理位置的搜索,比如某个位置,附近1公里内的POI点,类似这样的功能都是基于geohash算法实现的。 首先看看维基百科的定义 Geohash is a public domain geocode system invented in 2008 by Gustavo Niemeyer[1], which encodes a geographic location into a short string of letters and digits. It is a hierarchical spatial data structure which subdivides space into buckets of grid shape, which is one of the many applications of what is known as a Z-order curve, and generally space-filling curves. ...

November 12, 2019 · 2 min

聊聊关于es打分的有趣现象

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 1. 引子 公司内部有简单的搜索引擎,使用ES搭建。 前两天测试人员问我,为什么同一个查询条件,同一条数据,多次查询。score会发生变化。经过验证,确实存在这种问题,那么这种情况到底怎么产生的呢? 2. 例子 来造个例子 2.1 创建index curl -XPUT -H "Content-Type: application/json" dev1:9200/test -d ' { "settings": { "index.number_of_replicas": "2", "index.number_of_shards": "1" }, "mappings": { "_default_": { "dynamic_templates": [], "properties": { "brand": { "type": "keyword" } } } } } 2.2 写入数据 第1次执行 insert1.py import requests for i in range(500): url = "http://dev1:9200/test/car/%d" % (i) res = requests.put(url, json={"brand":"buick", "age":i}) print(i, res.status_code) 第2次执行 insert2.py ...

June 20, 2019 · 2 min

ES内部分享

ES内部分享 1. ES简介 ElasticSearch是Elastic公司开发的开源分布式搜索引擎 开源 分布式 全文检索 OLAP(结合kibana使用) Resful API NoSQL database 1.1 和Lucene的关系 { "name": "uf_-1wJ", "cluster_name": "UT", "cluster_uuid": "xvGp84DyQVOSxLXP43oDpA", "version": { "number": "6.2.4", "build_hash": "ccec39f", "build_date": "2018-04-12T20:37:28.497551Z", "build_snapshot": false, "lucene_version": "7.2.1", "minimum_wire_compatibility_version": "5.6.0", "minimum_index_compatibility_version": "5.0.0" }, "tagline": "You Know, for Search" } 简单而言,ES是Lucene的分布式版本,当然扩充了接口和在线分析功能 1.2 基本概念 1.2.1 索引层面 index type doc term 1.2.2 倒排索引 正常顺序 doc -> term 倒排索引 term -> doc 1.2.2 集群层面 Cluster Node Shard Segment 多种角色 Master-eligible node 2)Data node Ingest node Tribe node coordinating node ...

December 24, 2018 · 1 min

elasticsearch中自定义doc的路由(routing)规则

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 1. 前言 前几天有人在群里问,es是否可以指定某个字段为路由值。ES自定义的doc的路由,不过es的操作是,在写入一个doc时,指定doc的routing key。 2. 例子 2.1 创建一个新的index PUT /my_index2 { "settings": { "index": { "number_of_shards": 2, "number_of_replicas": 1 } } } index只有2个shard,shard 0和 shard 1 2.2 设置mapping PUT /my_index2/_mapping/student { "_routing": { "required": true }, "properties": { "name": { "type": "keyword" }, "age": { "type": "integer" } } } 2.3 指定doc路由 PUT /my_index2/student/1?routing=key1 { "name":"n1", "age":10 } PUT /my_index2/student/2?routing=key1 { "name":"n2", "age":10 } PUT /my_index2/student/3?routing=key1 { "name":"n3", "age":10 } 上面的3条命令会使得doc1、2、3放置在同一个shard上 shard 0 ...

December 12, 2018 · 1 min

Lucene索引结构漫谈

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 前言 注意: 本文基于Lucene 3.0.2, 目前Lucene的版本最新已经是7.3.x 虽然Lucene的版本变化较大, 但是索引结构已经构建它的核心思想并没有发生。 Lucene是solr和Elasticsearch的基础,汽车中的引擎,它的每次改版都会引起上层系统的巨大变化。研究它对于提升查询性能,降低存储开销有非常大的帮助。 笔者有三年多的ES使用经验,但是真正踏踏实实探究Lucene和ES也是最近时间的事情。 重要 首先,推荐的是一本书《Lucene实战》这本书的作者有好几个都是Lucene的核心开发人员,因此对Lucene的理解是非常透彻的, 非常推荐。 推荐索引文件的查看工具Luke, 它可以打开Lucene和ES的索引文件,直观的观察它们的内部数据 1. 索引文件列表 Lucene有2种文件格式 1.1 CompoundFile == false -rw-r--r-- 1 zhuwei wheel 1471 6 5 15:44 _2.fdt -rw-r--r-- 1 zhuwei wheel 12 6 5 15:44 _2.fdx -rw-r--r-- 1 zhuwei wheel 66 6 5 15:44 _2.fnm -rw-r--r-- 1 zhuwei wheel 323 6 5 15:44 _2.frq -rw-r--r-- 1 zhuwei wheel 8 6 5 15:44 _2.nrm -rw-r--r-- 1 zhuwei wheel 442 6 5 15:44 _2.prx -rw-r--r-- 1 zhuwei wheel 61 6 5 15:44 _2.tii -rw-r--r-- 1 zhuwei wheel 2611 6 5 15:44 _2.tis -rw-r--r-- 1 zhuwei wheel 9 6 5 15:44 _2.tvd -rw-r--r-- 1 zhuwei wheel 1647 6 5 15:44 _2.tvf -rw-r--r-- 1 zhuwei wheel 20 6 5 15:44 _2.tvx -rw-r--r-- 1 zhuwei wheel 20 6 5 15:44 segments.gen -rw-r--r-- 1 zhuwei wheel 233 6 5 15:44 segments_4 1.2 CompoundFile == true total 33976 -rw-r--r-- 1 zhuwei wheel 2459065 7 31 13:17 _0.cfs -rw-r--r-- 1 zhuwei wheel 13468962 7 31 13:17 _0.cfx -rw-r--r-- 1 zhuwei wheel 1451842 7 31 13:17 _1.cfs -rw-r--r-- 1 zhuwei wheel 20 7 31 13:17 segments.gen -rw-r--r-- 1 zhuwei wheel 442 7 31 13:17 segments_2 组合文件只是将原来放在多个文件中的数据整合到少数的几个文件中,减少了打开的文件描述符的数量,其它并没有大的区别,所以我们重点来看非组合文件。 ...

July 31, 2018 · 3 min

聊聊Elasticsearch的集群状态的管理和维护

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 注意 本文参考的ES 5.0.1的源码 1. 查看集群状态 可以通过API查看集群状态 GET /_cluster/state 大致可以得到如下内容 version 集群状态数字版本号 每次更新version + 1 集群重启version不会置0(只会单调增) state_uuid 是集群状态字符串版本号(UUID) master_node master节点 nodes 该版本中的所有节点信息 routing_table 和 routing_nodes 都是描述不同index上的shard在node上的分布关系 2. 集群状态的维护 ES源码中集群状态的对应类为ClusterState.java The cluster state can be updated only on the master node. All updates are performed by on a single thread and controlled by the {@link ClusterService}. After every update the {@link Discovery#publish} method publishes new version of the cluster state to all other nodes in the cluster. In the Zen Discovery it is handled in the {@link PublishClusterStateAction#publish} method ...

July 12, 2018 · 2 min

elasticsearch 中暂时移除一个节点

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 前言 在维护ES集群的过程中,我们会经常遇到将某个ES实例临时下线,比如机器换硬盘,系统参数调整,调整完毕后,再将ES实例重新上线。ES提供了非常便利的API来支持这一点。 操作过程 比如我们有这样一个ES集群,node-2需要临时下线 step 1 PUT _cluster/settings { "transient" : { "cluster.routing.allocation.exclude._name" : "node-2" } } 注意 这个操作是transient集群重启后,这个设置会失效 step 2 step1 配置完成以后,我们就会看到shard在集群中开始迁移,待迁移完成以后,对node-2进行处理 step 3 PUT _cluster/settings { "transient" : { "cluster.routing.allocation.exclude._name" : "" } } 只要让_name匹配不到对用的node即可 总结 除了_name 之外, 还可以用_ip、_host进行匹配 参考资料 Shard Allocation Filtering 请我喝瓶饮料

June 11, 2018 · 1 min

我在数据库方面踩过的"坑"

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 前言:前段时间在公司内部做了一个分享总结了部分我在使用各种数据库方面的遇到的问题。也在这里分享给大家。强调一下,这里的坑,我是打了引号的,有些坑,不过是某种数据库的特点,或者因为我们错误的事情而引出了问题,并不一定完全就是这种数据库有问题。 1. 业务篇 1)业务场景 不合理的业务设计,永远是对程序员最大的伤痛 在我维护的系统中有这样一种场景,用户要一次性下载全年或者半年的舆情数据,数据量会很大,单个任务就会达到数百万条数据。任何一个系统要在短时间内吞吐数据数百万条记录,也不是件很轻松的事情,尤其当这样的任务很多的时候。 目前这个时间跨度已经被调整成了3个月。说到这里不经让我想到12306错开时间发售火车票。 任何时候从业务角度的优化,总能带来立竿见影的效果 2) 字段设计 在我维护的某个系统中,同一种指标,在不同的表中,被存成了不同的字段名,这给我们带来了巨大的痛苦。所以建议对于同一种指标,或者事物使用同样的字段名(名称)进行表达、存储,否则后期光转换都要人命 3)表结构的反范式设计 大数据场景下,不要受到关系数据库范式设计的太多影响 数据机构能够立体的,尽量立体,不要扁平化 以新浪微博的一条转发举例 一条转发会包含有 这条微博的作者 这条微博的内容 text 原创微博retweeted_status 原创微博的内容 retweeted_status.text 原创微博的作者 retweeted_status.user … 一条记录就包含了这条转发,以及与这条转发相关的大部分内容,在实际使用时,无需连表查询可以方便的用NoSQL 数据库进行存储 { "created_at": "Tue May 31 17:46:55 +0800 2011", "id": 11488058246, "text": "求关注。", "source": "<a href="http://weibo.com" rel="nofollow">新浪微博</a>", "favorited": false, "truncated": false, "in_reply_to_status_id": "", "in_reply_to_user_id": "", "in_reply_to_screen_name": "", "geo": null, "mid": "5612814510546515491", "reposts_count": 8, "comments_count": 9, "annotations": [], "user": { "id": 1404376560, "screen_name": "zaku", "name": "zaku", "province": "11", "city": "5", "location": "北京 朝阳区", "description": "人生五十年,乃如梦如幻;有生斯有死,壮士复何憾。", "url": "http://blog.sina.com.cn/zaku", "profile_image_url": "http://tp1.sinaimg.cn/1404376560/50/0/1", "domain": "zaku", "gender": "m", "followers_count": 1204, "friends_count": 447, "statuses_count": 2908, "favourites_count": 0, "created_at": "Fri Aug 28 00:00:00 +0800 2009", "following": false, "allow_all_act_msg": false, "remark": "", "geo_enabled": true, "verified": false, "allow_all_comment": true, "avatar_large": "http://tp1.sinaimg.cn/1404376560/180/0/1", "verified_reason": "", "follow_me": false, "online_status": 0, "bi_followers_count": 215 }, "retweeted_status": { "created_at": "Tue May 24 18:04:53 +0800 2011", "id": 11142488790, "text": "我的相机到了。", "source": "<a href="http://weibo.com" rel="nofollow">新浪微博</a>", "favorited": false, "truncated": false, "in_reply_to_status_id": "", "in_reply_to_user_id": "", "in_reply_to_screen_name": "", "geo": null, "mid": "5610221544300749636", "annotations": [], "reposts_count": 5, "comments_count": 8, "user": { "id": 1073880650, "screen_name": "檀木幻想", "name": "檀木幻想", "province": "11", "city": "5", "location": "北京 朝阳区", "description": "请访问微博分析家。", "url": "http://www.weibo007.com/", "profile_image_url": "http://tp3.sinaimg.cn/1073880650/50/1285051202/1", "domain": "woodfantasy", "gender": "m", "followers_count": 723, "friends_count": 415, "statuses_count": 587, "favourites_count": 107, "created_at": "Sat Nov 14 00:00:00 +0800 2009", "following": true, "allow_all_act_msg": true, "remark": "", "geo_enabled": true, "verified": false, "allow_all_comment": true, "avatar_large": "http://tp3.sinaimg.cn/1073880650/180/1285051202/1", "verified_reason": "", "follow_me": true, "online_status": 0, "bi_followers_count": 199 } } } 2. hbase 篇 1)无法建立索引 hbase 最大的问题是无法建立索引 两个变象建立索引的办法 ...

January 1, 2018 · 3 min

UTF8 encoding is longer than the max length 32766

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 起因:同事在向ES插入数据时,收到了如下错误 mapping结构如下: { "test": { "mappings": { "test_ignore32766": { "properties": { "message": { "type": "string", "index": "not_analyzed" } } } } } } { "error": "RemoteTransportException[[Pietro Maximoff][inet[/10.1.1.51:9300]][indices:data/write/index]]; nested: IllegalArgumentException[Document contains at least one immense term in field=\"message\" (whose UTF8 encoding is longer than the max length 32766), all of which were skipped. Please correct the analyzer to not produce such terms. The prefix of the first immense term is: '[-28, -72, -83, -27, -101, -67, -25, -69, -113, -26, -75, -114, -26, -83, -93, -27, -100, -88, -25, -69, -113, -27, -114, -122, -26, -106, -80, -28, -72, -128]...', original message: bytes can be at most 32766 in length; got 69345]; nested: MaxBytesLengthExceededException[bytes can be at most 32766 in length; got 69345]; ", "status": 400 } 此问题的原因是这样的,message字段设置为not_analyzed,表示对这个字段不做分词索引,但对这个字段本身仍然是要索引的,也就说可以用term进行搜索 ...

January 1, 2018 · 1 min