es学习


数据整合
image
image
基于海量数据的搜索与分析,性能很强大

大数据的检索和分析

es概览

几个分布式搜索引擎的区别

倒排索引 (所有搜索引擎共有的特点)
lucene: 基于java的全文搜索引擎(高性能,功能全,无分布式、无高可用);是基于Java的类库, 其中集成了许多api方法; 可以理解Lucene是一个jar包; 只能结合Java使用; 集群十分复杂,需要自己实现;
solr与es都是基于lucene的搜索引擎;solr本质上是对Lucene进行的一层封装, Apche的开源项目;可以以容器的方式进行部署;可以实现集群;可靠性,容错性高
solr可tomcat部署;
es支持pb级 (查询搜索很快);支持分布式;restful接口,可供其他语言使用; 可扩展性更高;ES为用户提供近实时(速度很快)的搜索服务
GitHub 之前用的 solr 后续替换了ES , 使用ES的查询搜索速度是相当快的;ES官网 https://www.elastic.co/cn/what-is/elasticsearch
es用途:

  • 应用程序搜索
  • 网站搜索
  • 企业搜索
  • 日志处理和分析
  • 基础设施指标和容器监测
  • 应用程序性能检测
  • 地理空间数据分析和可视化
  • 安全分析
  • 业务分析

核心术语

image
image

索引  index  相当于数据库中的 表
类型  type (新版ES中 已经没有类型了, 相当于分类/类别/分组的概念) (6.x之前可以使用) 表逻辑类型 (某张表index,  这个表可能逻辑上都归类为吃的商品, 这个归类 :吃就是类型)
文档  document相当于数据库中的行  一行数据
字段  fields 对应数据库中的 列
映射  mapping   表结构定义 schema 类型,是否是分词
近实时  NRT       新增文档在1s内可被搜索到
节点  node  每一个服务器
分片  shard    shard = primary shard(主分片)把索引库拆分为多份,分别放在不同的节点上,比如有3个节点,3个节点的所有数据加在一起是一个完整的索引库。分别保存到三个节点上,目的为了水平扩展,提高吞吐量。
备份  replica  = replica shard(备份节点)每个shard的备份。

倒排索引

去根据单词搜索文档,搜索的性能比正排索引来的高
image

不仅可以记录属性值,还可以记录单次频率和出现的位置,重复次数(计分)

es 安装

https://class.imooc.com/lesson/1231#mid=29315
创建索引后,都会出现一个Unassigned,怎么去除呢?
看文档:https://www.cnblogs.com/mzli/p/12273735.html
ulimit -a 查看配置进程数

es-head可视化插件安装

google插件商店里有

手动安装
elasticsearch.conf配置Networt 模块
image

es集群状态

green 所有的主分片和副本分片都已经分配。你的集群式100%可用的。
yellow 所有的主分片已经分片,但至少还有一个副本是缺失的。不会有数据丢失,所以搜索结果依然是完整的。
red 至少一个主分片都在缺失中。这意味着你在缺少数据:搜索只能返回部分数据,而分配到这个分片上的写入请求会返回一个异常

es语法

es基本命令

索引相关命令

https://class.imooc.com/lesson/1231#mid=29316

es索引mapping设置

image
index:false 默认情况设置为true (可以不写); 设置为false,不被索引,在查询的时候不会被查询到(列如密码就使用这个)
keyword精确匹配,不会被分词;text会被分词查询
https://class.imooc.com/lesson/1231#mid=29317
mapping结构可以设置数组,但是数组的元素类型要一致,都是string或者integer,不能两个混在一起

文档操作

  • 文档添加
    (自动设置mapping)
    image

https://class.imooc.com/lesson/1231#mid=29318
用法put 竟然也可以添加数据,如果不设置索引ID 就必须用post了

  • 文档删除
    并不是从磁盘上真正的删除,而是逻辑删除;
    DELETE /my_doc/_doc/1
  • 文档更新
    • 局部
    POST /my_doc/_doc/1/_update
    {
    	"doc": {
    		"name": "慕课"
    	}
    }
    
    • 全量替换:
    PUT /my_doc/_doc/1
    {
    	 "id": 1001,
    	"name": "imooc-1",
    	"desc": "imooc is very good, 慕课网非常牛!",
    	"create_date": "2019-12-24"
    }
    
    

Luence需要全量替换 (所有属性字段值都要写)
es底层就是Luence,只不过es的post增量方法是对 做了一层二次封装;

每次修改/删除后, version都会改变, 删除也相当于一次修改(修改了逻辑删除状态),
即使删除不存在的数据,version也会改变
https://class.imooc.com/lesson/1231#mid=29319

乐观锁更新

https://class.imooc.com/lesson/1231#mid=29321

ES DSL语法

Domain Specific Language
特定领域语言
https://class.imooc.com/lesson/1231#mid=29326
查询更灵活,有利于复杂查询

查询所有和分页

查询指定字段及分页

POST     /shop/_doc/_search
{
    "query": {
        "match_all": {}
    },
    "_source": ["id", "nickname", "age"],
	"from": 0,
    "size": 10

}

https://class.imooc.com/lesson/1231#mid=29327

term/match

term方式,【不会】对查询条件做分词,直接把查询条件的完整词汇进行匹配搜索。
match方式,【会】对查询条件做分词,之后对每个分词进行匹配搜索。
terms搜索是tag的or結合 不是and
https://class.imooc.com/lesson/1231#mid=29328
term关键字的确不对关键字进行分词,但是不代表字段本身不会分词。
既然如此的话,term查询之前,实际上字段的内容可能已经经过分词处理了,所以term对整段文字进行匹配才会查不到数据。

match(operator)/ids

https://class.imooc.com/lesson/1231#mid=29330

POST     /shop/_doc/_search
{
    "query": {
        "match": {
            "desc": "慕课网"
        }
    }
}
# 等同于
{
    "query": {
        "match": {
            "desc": {
                "query": "xbox游戏机",
                "operator": "or",
				"minimum_should_match": "60%"
            }
        }
    }
}
{
    "query": {
        "ids": {
            //"type": "_doc",
            "values": ["1001", "1010", "1008"]
        }
    }
}
# 相当于 select * from shop where desc='xbox' or|and desc='游戏机'

match_phrase

match_phrase 词组匹配,顺序相同且连续
slop允许跳过的词数量
https://class.imooc.com/lesson/1231#mid=29329

multi_match/boost

https://class.imooc.com/lesson/1231#mid=29331
image
配置权重分数比列

  • 查询出的数据中都是按照 "_soure"的大小值进行排序;这些分数是通过文档每个字段匹配关键字汇总得出的比列分数
  • 可以给某个字段配置权重(对应匹配分数会乘以对应的权重), 让如果某一字段列出现了关键字分词,那么他出现的"_soure"就更高,也就说明他的排名会变的更高,更容易被用户看到,

bool(must/not/should)

可以通过es-head去自动化生成dsl语句,避免手动操作

bool:{
    must:必须匹配,当于数据库中的 AND, must中的内容必须要同时满足
    must_not: 不匹配, 相当于数据库中的 != ,must_not中的内容必须都保证不满足
    should: 或 ,相当于数据库中的 OR, should中的内容满足其一即可
}
三者按实际先后顺序and拼接,以上面查询出来的结果作后续查询条件的输入,should不会对must结果造成影响
boost加权,提高分数,让数据排在更前面。

https://class.imooc.com/lesson/1231#mid=29332

过滤器(post_filter)

不会根据词语去检索,不会计算数据相关匹配度分数,是根据query已经检索出来的结果作过滤,性能较高
https://class.imooc.com/lesson/1231#mid=29333
不可以复合使用

排序

  • es搜索结果默认是按照 "_soure" 关键字所占文档分数比例进行排序的;
  • 可以组合排序, 现根据某属性进行排序, 排完序如果有重复的再根据下一个属性进行排序
  • type是text,由于分词的原因,不能排序;是keywords的话 可以进行排序;text需要给分词增加一个fields且type是keyword的属性,搜索用a.b的形式排序
    https://class.imooc.com/lesson/1231#mid=29334

关键字高亮

https://class.imooc.com/lesson/1231#mid=29524

拓展

查询官方文档
https://class.imooc.com/lesson/1231#mid=29526

深度分页

当查询的[当前页数--from]越大,说明查询的分页深度越深, 这是会影响的一定的性能的
es会控制页数在10000以内,以防止分页深度太深造成的性能上的损害;
image
和常规分页逻辑不同; es是先全部拿出来,再从中取 size 条数据; 这个过程数据量一多必然会造成性能的损耗
(正常分页逻辑是每次查询, pagesize条数据,切换页数的时候在进行下一次查询)
控制分页数, 将搜索结果控制在100页之内(这样数据量不会超过1万,不会出现深度分页)

滚动搜索

https://class.imooc.com/lesson/1231#mid=29529

  • 针对于大量数据的查询
  • 第一次查询进行初始化
  • 通过scroll_id,来区分,以便进行下一次的滚动查询
  • 在查询期间是快照查询, 如果在此期间有 被查询数据进行了修改, 那么用户在查询期间是不会查询出变化的、
    可以用来做批量导出的操作,当数据量很多的时候,使用 scroll来做批量导出是完全没有问题的

查看/修改设置

https://class.imooc.com/lesson/1231#mid=29528

批量操作

批量查询

批量搜索_mget与query的主要区别
_mget如果没有查询到,会返回一个"found": false
query如果没有查询到,则直接不返回结果。

/shop/_mget
{
    "ids":["1001","1002","1111"]
}
/_search
{
    "query": {
        "ids": {
            "type": "_doc",
            "values":["1001", "1003", "1005"]
        }
    }
}

bulk(批量更新/修改/查询)

https://class.imooc.com/lesson/1231#mid=29530
bulk 批量数据操作请求会加载到内存中,不宜过多,有阈值,1000-5000,一般1000差不多
https://www.elastic.co/guide/cn/elasticsearch/guide/current/bulk.html

es分词器

standard :默认分词,单词会被拆分,大小写会转换小写, 不支持中文。
simple:按照非字母分词(空格, 数字, 符号, 且会去除)。大写会转为小写。
whitespace :按照空格分词。忽略大小写。
stop: 去除无意义单词。比如the/a/an/is...;大写会转为小写
keyword:不做分词。把整个文本作为一个单独的关键词

POST /my_doc/_analyze
{
    "analyzer": "standard",
    "field": "name",
    "text": "text文本"
}
{
    "analyzer": "standard",
    "text": "My name is Peter Parker,I am a Super Hero. I don't like the Criminals."
}


中文分词器

github elasticsearch-analysis-ik插件;
需要注意藁本的插件,不需要建立ik目录了,直接解压;以及目录不能有空格以及中文等非字符;

自定义中文字典

.在{es}/plugins/ik/config下创建:custom.dic自定义中文字典,也支持站点形式维护txt文件

es集群

es集群架构原理

单个ES节点也是可以为用户服务的,一旦数据量庞大,单个节点可能服务不过来,因此可以增加节点来做集群以提高整个服务的吞吐量,
每个node shard都有一个进程,并且每个shard是并行处理的,提高吞吐量,也就是分布式计算处理的能力(平均分配)
分片可以提高吞吐量,提高性能,因为每个shard都有一个es进程,都可以处理请求,增加节点,也可以达到扩容的机制,水平扩展,replica冗余备份,高可用,以免shard宕机数据丢失。
image

集群概念

image
高可用:保证主分片不能和备份分片放在同一台服务器节点; 防止服务器挂掉后,其中主备分片的数据都丢失了!因此单机无法实现集群,必须两台以上
https://class.imooc.com/lesson/1231#mid=29532

搭建集群

高版本cluster.initial_master_nodes这个参数必须配置多个master节点,看官方api也是推荐>=3

node.master:true, 代表这个节点未来可能成为master
node.data:true,数据节点
discovery.seed.hosts:服务节点,所有节点ip
查看配置文件
more elasticsearch.yml | grep ^[^#] 过滤掉注释

修改配置文件

# 配置集群名称,保证每个节点的名称相同,如此就能都处于一个集群之内了
cluster.name: imooc-es-cluster

# 每一个节点的名称,必须不一样
node.name: es-node1

# http端口(使用默认即可)
http.port: 9200

# 主节点,作用主要是用于来管理整个集群,负责创建或删除索引,管理其他非master节点(相当于企业老总)
node.master: true

# 数据节点,用于对文档数据的增删改查
node.data: true

# 集群列表
discovery.seed_hosts: ["192.168.1.184", "192.168.1.185", "192.168.1.186"]

# 启动的时候使用一个master节点
cluster.initial_master_nodes: ["es-node1"]
# 配置访问ip
network.publish_host: 192.168.33.31

集群测试

es进行集群配置之后,创建索引的时候,会自动完成主分片和备份分片的配置;且主备不会出现在同一台服务器上;
image

宕机测试

master宕机:
会自动选择一个 配置了 【node.master: true】的服务器节点重新作为master;
原来的master恢复后,原来的那个master会作为 从节点继续服务, 而不会回到主节点
image
salve从宕机: 将宕机从节点的 主备分片在分配到其他服务器节点上;
宕机后分片会重新同步分配

出处

https://class.imooc.com/lesson/1231#mid=29531

集群脑裂

出现的情况:
当服务器有一个节点想成为master,只要有一票就可以成为主节点,当宕机的master节点恢复服务时,有可能自己给自己投了一票,导致自己又重新成为了master,就导致集群被拆分
解决方案:
至少要有半数以上的节点投票,才能成为master
而不能用最小投票人数为1
discovery.zen.minimum_master_nodes=(N/2)+1
image
N代表 config中 node.master 被设置为 true 的数量
ES 7.x 没有脑裂的问题(已经不支持这个参数了,由es自己进行管理)

文档读写原理

文档写操作

  • 用户访问服务器和es进行交互, 服务器都是指定一台 es节点服务器作为交互方;
  • 当服务器访问的这台es服务器时,这台服务器就会被es认作为 es集群中的协调节点(负责接收 响应用户请求);
    • 会做一个算法(hash算法),通过算法结果来决定 具体写到哪一个主分片;(路由转发)
  • 文档存入主分片之后, 再将数据同步到副本分片上
  • 当主分片和副本分片的文档数据都写入之后, 再由[协调节点]响应客户端结果
    image

文档读操作

image

  • 客户端请求 协调节点;
    • 协调节点 针对 文档id 做 路由转发(采用的算法类似hash算法,计算出文档保存在哪个位置)
  • 之后在 轮询的方式 转发到 存储该文档的 主节点或者备份节点(这么做可以分担请求压力提高效率)
  • 之后数据返回给协调节点,由协调节点响应客户端
    负载均衡,高负载

springboot整合es

queryForPage可以检索文档数据,以List形式返回
https://blog.csdn.net/weixin_51408465/article/details/131847032
https://blog.csdn.net/UbuntuTouch/article/details/120948876

logstash数据采集引擎

以id作为判断 来添加数据的话 有弊端,只能添加 DB中新增的数据,以前同步过了但是有更新的数据就不会被再同步了
所以会采用以update_time为判断 依据
image

logstash 用数据进行同步
1、数据采集(从数据库等任意数据源)
2、以id或update_time作为同步边界
3、logstash-input-jdbc插件
4、logstash要和es版本一致
5、索引要手动创建(如数据库表要先创建,再进行导入数据)
image
通过定时任务来进行扫描,同步。
https://class.imooc.com/lesson/1231#mid=29536

logstash配置mysql同步es

  1. 创建sync目录
  2. copy数据库驱动到sync目录
  3. sync目录创建logstash-db-sync.conf
    input {
    	jdbc {
    		# 设置 MySql/MariaDB 数据库url以及数据库名称
    		jdbc_connection_string => "jdbc:mysql://192.168.1.6:3306/foodie-shop-dev?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true"
    		# 用户名和密码
    		jdbc_user => "root"
    		jdbc_password => "root"
    		# 数据库驱动所在位置,可以是绝对路径或者相对路径
    		jdbc_driver_library => "/usr/local/logstash-6.4.3/sync/mysql-connector-java-5.1.41.jar"
    		# 驱动类名
    		jdbc_driver_class => "com.mysql.jdbc.Driver"
    		# 开启分页
    		jdbc_paging_enabled => "true"
    		# 分页每页数量,可以自定义
    		jdbc_page_size => "10000"
    		# 执行的sql文件路径
    		statement_filepath => "/usr/local/logstash-6.4.3/sync/foodie-items.sql"
    		# 设置定时任务间隔  含义:分、时、天、月、年,全部为*默认含义为每分钟跑一次任务
    		schedule => "* * * * *"
    		# 索引类型
    		type => "_doc"
    		# 是否开启记录上次追踪的结果,也就是上次更新的时间,这个会记录到 last_run_metadata_path 的文件
    		use_column_value => true
    		# 记录上一次追踪的结果值
    		last_run_metadata_path => "/usr/local/logstash-6.4.3/sync/track_time"
    		# 如果 use_column_value 为true, 配置本参数,追踪的 column 名,可以是自增id或者时间
    		tracking_column => "updated_time"
    		# tracking_column 对应字段的类型
    		tracking_column_type => "timestamp"
    		# 是否清除 last_run_metadata_path 的记录,true则每次都从头开始查询所有的数据库记录
    		clean_run => false
    		# 数据库字段名称大写转小写
    		lowercase_column_names => false
    	}
    }
    output {
    	elasticsearch {
    		# es地址
    		hosts => ["192.168.1.187:9200"]
    		# 同步的索引名
    		index => "foodie-items"
    		# 设置_docID和数据相同
    		document_id => "%{id}"
    	}
    	# 日志输出
    	stdout {
    		codec => json_lines
    	}}
    
    
  4. foodie-items.sql
    :sql_last_value是一个变量,表示每次同步完的时间
     SELECT
     i.id as itemId,
     i.item_name as itemName,
     i.sell_counts as sellCounts,
     ii.url as imgUrl,
     tempSpec.price_discount as price,
     i.updated_time as updated_time
     FROM
    	 items i
     LEFT JOIN
    	 items_img ii
     on
    	 i.id = ii.item_id
     LEFT JOIN
    	 (SELECT item_id,MIN(price_discount) as price_discount from items_spec GROUP BY item_id) tempSpec
     on
    	 i.id = tempSpec.item_id
     WHERE
    	 ii.is_main = 1
    	 and
    	 i.updated_time >= :sql_last_value
    
  5. 启动logstash
    ./logstash -f /usr/local/logstash-6.4.3/sync/logstash-db-sync.conf

https://class.imooc.com/lesson/1231#mid=29537

问题记录

记住同步数据的时候如果有多余的索引要删除
比如案例中只有 foodie-items这个索引就只保留这个索引就可以了
不要添加多余的索引
这是一个坑

logstash修改默认同步模板

使用http://url:9200/_template/logstash获取模板,在string_fields中添加"analyzer": "ik_max_word"来设置分词器
image
image

  1. 修改模板如下
{
    //可以将自定义模板中的order增大(默认的logstash模板order为0)以提高优先级
    "order": 0,
    "version": 1,
    "index_patterns": ["*"],
    "settings": {
        "index": {
            "refresh_interval": "5s"
        }
    },
    "mappings": {
        "_default_": {
            "dynamic_templates": [
                {
                    "message_field": {
                        "path_match": "message",
                        "match_mapping_type": "string",
                        "mapping": {
                            "type": "text",
                            "norms": false
                        }
                    }
                },
                {
                    "string_fields": {
                        "match": "*",
                        "match_mapping_type": "string",
                        "mapping": {
                            "type": "text",
                            "norms": false,
                            "analyzer": "ik_max_word",
                            "fields": {
                                "keyword": {
                                    "type": "keyword",
                                    "ignore_above": 256
                                }
                            }
                        }
                    }
                }
            ],
            "properties": {
                "@timestamp": {
                    "type": "date"
                },
                "@version": {
                    "type": "keyword"
                },
                "geoip": {
                    "dynamic": true,
                    "properties": {
                        "ip": {
                            "type": "ip"
                        },
                        "location": {
                            "type": "geo_point"
                        },
                        "latitude": {
                            "type": "half_float"
                        },
                        "longitude": {
                            "type": "half_float"
                        }
                    }
                }
            }
        }
    },
    "aliases": {}
}
  1. logstash配置做如下修改
# 定义模板名称
template_name => "myik"
# 模板所在位置
template => "/usr/local/logstash-6.4.3/sync/logstash-ik.json"
# 重写模板
template_overwrite => true
# 默认为true,false关闭logstash自动管理模板功能,如果自定义模板,则设置为false
manage_template => false

  1. 重新启动同步
./logstash -f /usr/local/logstash-6.4.3/sync/logstash-db-sync.conf

https://class.imooc.com/lesson/1231#mid=29538

logstash如何同步删除

  1. 逻辑删除,通过标识和更新时间,更新es中数据标识为已删除
  2. 通过设置linux定时任务定时删除一定时间前的es数据(例如7天前)
    curl -XDELETE "http://elasticseatch:9200/index"

脑图

image

复习

https://class.imooc.com/lesson/1231#mid=29539

备注

有兴趣可以去了解一下磁盘阵列或者NAS的raid0+1

posted @   bePatient  阅读(14)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示