elasticsearch背景 https://www.cnblogs.com/Neeo/p/10304892.html
我们建立一个网站或应用程序,并要添加搜索功能,但是想要完成搜索工作的创建是非常困难的。我们希望搜索解决方案要运行速度快,我们希望能有一个零配置和一个完全免费的搜索模式,我们希望能够简单地使用JSON通过HTTP来索引数据,我们希望我们的搜索服务器始终可用,我们希望能够从一台开始并扩展到数百台,我们要实时搜索,我们要简单的多租户,我们希望建立一个云的解决方案。因此我们利用Elasticsearch来解决所有这些问题及可能出现的更多其它问题。
什么是elasticsearch?
一个搜素服务器,它提供了一个分布式多用户能力的全文搜索引擎,也可以说是一个数据库.基于RESTful web接口,也可以作为数据库使用。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。
elasticsearch特点
- 分布式实时文档存储,并将每一个字段都编入索引,使其可以被搜索。
- 实时分析的分布式搜索引擎。
- 可以扩展到上百台服务器,处理PB级别的结构化或非结构化数据。
应用场景
可以作为一个搜素的插件应用到项目中
elasticsearch组织架构
elasticsearch中文档,类型,索引的关系
①elasticsearch是面向文档的,那么就意味着索引和搜索数据的最小单位是文档;
- 自我包含,一篇文档同时包含字段和对应的值,也就是同时包含
key:value
- 可以是层次型的,一个文档中包含自文档,复杂的逻辑实体就是这么来的
- 灵活的结构,文档不依赖预先定义的模式,我们知道关系型数据库中,要提前定义字段才能使用,在elasticsearch中,对于字段是非常灵活的,有时候,我们可以忽略该字段,或者动态的添加一个新的字段。
- 文档是无模式的,也就是说,字段对应值的类型可以是不限类型的。
②类型是文档的容器,就像mysql一样,表是行的容器;
类型中对于字段的定义称为映射,比如name
映射为字符串类型。
③索引是映射类型的容器,elasticsearch中的索引是一个非常大的文档集合。索引存储了映射类型的字段和其他设置。然后它们被存储到了各个分片上了。
什么是节点和分片?
一个集群包含至少一个节点,而一个节点就是一个elasticsearch进程。节点内可以有多个索引。
默认的,如果你创建一个索引,那么这个索引将会有5个分片(primary shard,又称主分片)构成,而每个分片又有一个副本(replica shard,又称复制分片),这样,就有了10个分片。如下图
上图是一个有3个节点的集群,可以看到主分片和对应的复制分片都不会在同一个节点内,这样有利于某个节点挂掉了,数据也不至于丢失。
实际上,一个分片是一个Lucene索引,一个包含倒排索引的文件目录,倒排索引的结构使得elasticsearch在不扫描全部文档的情况下,就能告诉你哪些文档包含特定的关键字。
倒排索引
elasticsearch使用的是一种称为倒排索引的结构,采用Lucene倒排索作为底层。elasticsearch将索引被分为多个分片,每份分片是一个Lucene的索引。所以一个elasticsearch索引是由多个Lucene索引组成的。这种结构适用于快速的全文搜索,一个索引由文档中所有不重复的列表构成,对于每一个词,都有一个包含它的文档列表。
如下表,进一步理解倒排索引:
学科(原始数据) | 索引列表(倒排索引) | ||
id | 学科 | 语言 | id |
1 | 语文 | 语文 | 1,2,3 |
2 | 语文 | 数学 | 3,4 |
3 | 语文,数学 | ||
4 | 数学 |
MySQL,MongoDB,Elasticsearch对比
关系型数据库和非关系型数据库比对 | ||
MySQL | MongoDB | Elasticsearch |
数据库(database) | 数据库 | 索引(indices) |
表(tables) | 表(Collection) | types |
行(rows) | Documents | Documents |
字段(columns) | Field | Field |
总结:MySQL为关系型数据库,而MongoDB,Elasticsearch为非关系型数据库,由此看出两者的特点比较明显;
elasticsearch(集群)中可以包含多个索引(数据库),每个索引中可以包含多个类型(表),每个类型下又包含多个文档(行),每个文档中又包含多个字段(列)。
物理设计 ---> elasticsearch后台是如何处理这些数据的呢?elasticsearch将每个索引划分为多个分片,每份分片又可以在集群中的不同服务器间迁移。
注意:当然,这里需要补充的是,从elasticsearch
的第一个版本开始,每个文档都存储在一个索引中,并分配多个映射类型,映射类型用于表示被索引的文档或者实体的类型,但这也带来了一些问题(详情参见Removal of mapping types),导致后来在elasticsearch6.0.0
版本中一个文档只能包含一个映射类型,而在7.0.0
中,映射类型则将被弃用,到了8.0.0
中则将完全被删除。
elasticsearch的语法
1.基本语法写法
#基本语法 #PUT创建一文档(注意大写)t1的文档 PUT t1/doc/1 { "name":"可可" } #查询t1的文档索引信息 GET t1/doc/1 #删除索引 DELETE t1/doc/1 PUT t1/doc/2 { "name":"盼盼", "age":20 } GET t1 #返回t1所有的创建信息 GET _cat/indices #查询所有文档的信息 GET t1/_settings #查询t1的主分片和复制分片情况 GET t1/_mapping #查看t1的映射关系结构
创建一些数据来操作操作
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#是不是有种来到汉朝的感觉,没事,放松点,呵呵 PUT han/doc/1 { "name":"孝景帝", "from":"汉朝", "in_time":16, "info":"无为而治", "tags":["平定七国之乱","诛晁错"], "female":"窦太后" } PUT han/doc/2 { "name":"孝武帝", "from":"汉朝", "in_time":54, "info":"以战养战", "tags":["罢黜百家,独尊儒术","推恩令","平定北方匈奴","丝绸之路"], "female":"卫子夫" } PUT han/doc/3 { "name":"汉高祖", "from":"汉朝", "in_time":7, "info":"建立汉朝", "tags":["鸿门宴","灭秦,楚国"], "female":"吕雉" } PUT han/doc/4 { "name":"卫青", "from":"孝武帝", "in_time":2, "title":"关内侯", "info":"初伐匈奴", "tags":["奇袭龙城"] } PUT han/doc/5 { "name":"李广", "in_time":1, "from":"孝武帝", "title":"飞将军", "info":"射石搏虎", "tags":["平七国吴楚联军"] } PUT han/doc/6 { "name":"霍去病", "from":"孝武帝", "in_time":3, "title":"骠骑校尉", "info":"英年早逝,封景桓侯", "tags":["八百铁骑,直插敌后","平定朔方,打通西域"] } PUT han/doc/7 { "name":"李广利", "from":"孝武帝", "title":"贰师将军", "in_time":4, "info":"二征大宛", "tags":["征服大宛"] }
2.结构化查询(match相关)
"""match按关键字查询""" #match_all查询全部 GET han/doc/_search { "query": { "match_all": {} } }
#match指定字段查询,但是这样会查出来所有name字段中跟孝武帝相关的数据,列如孝景帝. GET han/doc/_search { "query": { "match": { "name":"孝武帝" } } } #单独查询某条数据match_phrase,只会查到name是'孝武帝'的数据 GET han/doc/_search { "query": { "match_phrase": { "name": "孝武帝" } } } #最左前缀查询,match_phrase_prefix,不记得字段信息了,智能匹配 GET han/doc/_search { "query": { "match_phrase_prefix": { "name": "霍" } } }
#多字段查询multi_match ,查到字段中含有"帝"的数据 GET han/doc/_search { "query": { "multi_match": { "query": "帝", "fields": ["name","title"] } } } #multi_match甚至可以match_phrase,match_phrase_prefix使用,只要指定type即可 GET han/doc/_search { "query": { "multi_match": { "query": "青", "fields": ["name"], "type": "phrase" } } } GET han/doc/_search { "query": { "multi_match": { "query": "孝", "fields": ["name"], "type": "phrase_prefix" } } }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#排序sort #降序 GET han/doc/_search { "query": { "match_all": {} }, "sort":[ { "in_time":{ "order":"desc" } } ] } #升序 GET han/doc/_search { "query": { "match_all": {} }, "sort": [ { "in_time": { "order": "asc" } } ] }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#过滤_source GET han/doc/_search { "query": { "match_all": {} }, "sort": [ { "in_time": { "order": "asc" } } ], "_source": [ "from", "in_time","name"] }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#分页 from从哪开始,size:展示条数,from,size也可以为-1 GET han/doc/_search { "query": { "match_all": {} }, "from":2, "size":2, "_source": "in_time" }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#高亮 highlight GET han/doc/_search { "query": { "match": { "from":"孝武帝" } }, "highlight":{ "pre_tags":"<b style='color:red;'>", "post_tags":"</b>", "fields":{ "from": {} } } }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#bool查询:must(and)/should(or)/must_not(not) #and GET han/doc/_search { "query": { "bool": { "must": [ {"match": { "in_time": "1" } }, { "match": { "from": "孝武帝" } } ] } } } #or GET han/doc/_search { "query": { "bool": { "should": [ {"match": { "from": "汉朝" } }, { "match": { "in_time": 54 } } ] } } } #not GET han/doc/_search { "query": { "bool": { "must_not": [ {"match": { "from": "孝武帝" } }, { "match": { "in_time": 54 } } ] } } }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#查询filter:gte(大于等于) gt(大于)lt(小于)lte(小于等于) GET han/doc/_search { "query": { "bool": { "must": [ { "match": { "from": "汉朝" } } ], "filter": { "range": { "in_time": { "gte": 10 } } } } } } #小于 GET han/doc/_search { "query": { "bool": { "must": [ { "match": { "from": "汉朝" } } ], "filter": { "range": { "in_time": { "lt": 10 } } } } } }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#聚合查询:avg,sum,max,min GET han/doc/_search { "query": { "match_all": {} }, "aggs": { "my_a1": { "avg": { "field": "in_time" } } } }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#分组 GET han/doc/_search { "query": { "match_all": {} }, "aggs": { "my_group": { "range": { "field": "in_time", "ranges": [ { "from": 20, "to": 60 } ] } } } } #分组再聚合 GET han/doc/_search { "query": { "match_all": {} }, "aggs": { "my_group": { "range": { "field": "in_time", "ranges": [ { "from": 10, "to": 60 } ] }, "aggs": { "my_sum": { "sum": { "field": "in_time" } } } } } }
3.映射
映射用来自定义一个文档及其包含的字段如何存储和索引的过程
例如,我们可以使用映射来定义:
- 哪些字符串应该被视为全文字段。
- 哪些字段包含数字、日期或者地理位置。
- 定义日期的格式。
- 自定义的规则,用来控制动态添加字段的的映射。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#映射mappings写法-01 dynamic没写默认为true,可以添加字段 PUT t3 { "mappings":{ "doc":{ "properties":{ "name":{ "type":"text" }, "age":{ "type":"long" } } } } } GET t3/_mapping PUT t3/doc/1 { "name":"窦颖", "age":17, "desc":"可爱" } GET t3/doc/_search { "query": { "match": { "age": 17 } } } #mappings写法-02 dynamic=false 不让添加字段,但不报错 PUT t4 { "mappings":{ "doc":{ "dynamic":false, "properties":{ "name":{ "type":"text" }, "age":{ "type":"long" } } } } } GET t4/_mapping PUT t4/doc/1 { "name":"颖", "age":19, "desc":"可ke爱" } #mappings写法-03 dynamic=strict 严格模式,只要添加就报错 PUT t5 { "mappings": { "doc":{ "dynamic":"strict", "properties":{ "name":{ "type":"text" } } } } } GET t5/_mapping PUT t5/doc/1 { "name":"coco" } #缺省/严格的时候不能添加字段 PUT t5/doc/2 { "name":"cici", "age":9 }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#index属性,类似于模糊查询配置,有两种状态,当true,我们的自定义字段可以实现模糊查询,false则会报错 PUT t6 { "mappings": { "doc":{ "properties":{ "title":{ "type":"text", "index":true }, "content":{ "type":"text", "index":false } } } } } PUT t6/doc/1 { "title":"es长路漫漫", "content":"py唯你作伴" } #报错 GET t6/doc/_search { "query": { "match": { "title":"漫漫" } } } GET t6/doc/_search { "query": { "match": { "content":"py" } } }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#copy_to,该属性允许我们将多个字段的值复制到组字段中,然后将组字段作为单个字段进行查询。 #copy_to写法-01 PUT t7 { "mappings": { "doc":{ "properties":{ "title":{ "type":"text", "copy_to":"full_name" }, "content":{ "type":"text", "copy_to":"full_name" }, "full_name":{ "type":"text" } } } } } PUT t7/doc/1 { "title":"aa", "content":"bb" } GET t7/doc/_search { "query": { "match": { "full_name": "bb" } } } #copy_to写法-02 PUT t8 { "mappings": { "doc":{ "properties":{ "title":{ "type":"text", "copy_to":["full_name1","full_name2"] }, "content":{ "type":"text", "copy_to":"full_name" }, "full_name1":{ "type":"text" }, "full_name2":{ "type":"text" } } } } }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#对象属性,mappings中嵌套结构写法,查询方式:info.addr PUT t9 { "mappings": { "doc":{ "dynamic":false, "properties":{ "name":{ "type":"text" }, "age":{ "type":"long" }, "info":{ "properties":{ "addr":{ "type":"text" }, "tel":{ "type":"text" } } } } } } } PUT t9/doc/1 { "name":"vov", "age":19, "info":{ "addr":"earth", "tel":"no" } } GET t9/doc/_search { "query": { "match": { "info.addr": "earth" } } }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#settings设置,设置主,复制分片. #number_of_shards主分片数量,默认5,number_of_replicas复制分片,默认1个 PUT w1 { "mappings": { "doc":{ "properties":{ "title":{ "type":"text" } } } }, "settings": { "number_of_shards": 3, "number_of_replicas": 2 } } GET w1
...待续