本篇文章包含以下内容:
- ES的介绍
- ELK在Linux系统下的部署以及各种坑
- ES在项目中的使用
思维导图:

1、背景
使用 elasticsearch,以下简称es 的几个原因如下
- 关系型数据库在进行模糊(%关键字%)搜索的时候,会全表扫描,查询非常慢
- 关系型数据库在关键字搜索时,并不支持全文分词搜索,比如用户本打算搜索:公众号-111,却手误:公号-111,es 可以根据分词的结果搜索出想要的结果。
- 在数据分析、日志分析上用到 es
2、es 基本概念
Elasticsearch 是一个分布式、RESTful 风格的搜索和数据分析引擎,适用于包括文本、数字、地理空间、结构化和非结构化数据等在内的所有类型的数据。Elasticsearch 在 Apache Lucene 的基础上开发而成,由 Elasticsearch N.V.(即现在的 Elastic)于 2010 年首次发布。
Elasticsearch 是文件存储,Elasticsearch 是面向文档型数据库,一条数据在这里就是一个文档,用 JSON 作为文档序列化的格式,比如下面这条用户数据:
{ "name":"name", "sex":0, "age":21 }
3、es 优势
- 分布式:横向可扩展性,增加服务器可直接配置在集群中
- 高可用:提供了复制功能,具有容错机制,能自动发现新的或失败的节点,重组和重新平衡节点数据
- 实时性:数据进入 es,可达到近实时搜索
- Restful api:json 格式的 RESTful 风格
- 全文检索:基于 lucene 的强大的全文检索能力
4、在linux系统中部署es
1、下载对应版本的es,这里下载了8.1.2
2、下载完成后,复制到服务器,解压到合适的位置
此处我解压到了/root/docker/elasticsearch文件夹下
tar -zxvf elasticsearch-8.1.2-linux-x86_64.tar.gz -C /root/docker/elasticsearch/
注:超级天坑,解压到上面的文件夹后怎么都找不到es自带的jdk,无法启动,把es解压到/usr/local后就可以了。然后跳过第三步都可以启动。
3、解决es强依赖jdk问题
由于es和jdk是一个强依赖的关系,所以当我们在新版本的ElasticSearch压缩包中包含有自带的jdk,但是当我们的Linux中已经安装了jdk之后,就会发现启动es的时候优先去找的是Linux中已经装好的jdk,此时如果jdk的版本不一致,就会造成jdk不能正常运行。
注:如果Linux服务本来没有配置jdk,则会直接使用es目录下默认的jdk,反而不会报错。
- 进入bin目录
cd /root/docker/elasticsearch/elasticsearch-8.1.2/bin
- 修改elasticsearch配置,将以下代码加入到文件开头
vim ./elasticsearch
############## 添加配置解决jdk版本问题 ############## # 将jdk修改为es中自带jdk的配置目录 export JAVA_HOME=/root/docker/elasticsearch/elasticsearch-8.1.2/jdk export PATH=$JAVA_HOME/bin:$PATH if [ -x "$JAVA_HOME/bin/java" ]; then JAVA="/root/docker/elasticsearch/elasticsearch-8.1.2/jdk/bin/java" else JAVA=`which java` fi
4、解决内存不足问题
进入config文件夹开始配置,使用vim编辑jvm.options:
默认配置如下: ##-Xms4g ##-Xmx4g 默认的配置占用内存太多了,调小一些: -Xms256m -Xmx256m
/root/docker/elasticsearch/elasticsearch-8.1.2/
5、创建专用用户启动ES
root用户不能直接启动Elasticsearch,所以需要创建一个专用用户,来启动ES
- 创建用户
useradd user-es
#设置密码 sudo passwd user-es root root
- 创建所属组:
chown user-es:user-es -R /root/docker/elasticsearch/elasticsearch-8.1.2
- 切换到user-es用户
su user-es
- 进入bin目录
cd /root/docker/elasticsearch/elasticsearch-8.1.2/bin
疑似记录错误?/usr/local/elasticsearch-8.1.2/bin/
- 启动elasticsearch
./elasticsearch
- 后台启动启动elasticsearch
./elasticsearch
-d
关闭es:
ps -ef | grep ela
kill <进程id>
6、启动ElasticSearch报错:error updating geoip database
解决方案:
在elasticsearch.yml中添加如下配置:
ingest.geoip.downloader.enabled: false 1
关闭geoip数据库的更新
7、修改elastic用户登录密码
在elasticsearch根目录下,输入:
./bin/elasticsearch-reset-password --username elastic -i
然后输入新的密码elastic。
于是原来的
elastic
0KskxivpPR-lGMsNZ-Ii
变成了
elastic
elastic
8、重新启动步骤
进入/usr/local/elasticsearch-8.1.2/bin/ 文件夹 !!!
切换user-es用户
杀死现有进程
ps -ef | grep ela
kill <进程id>
后台启动启动elasticsearch,进入bin目录
./elasticsearch
-d
9、文件描述符限制太低(max file descriptors [65535] for elasticsearch process is too low)
elasticsearch安装后启动时候,遇到此问题
问题翻译过来就是:elasticsearch用户拥有的可创建文件描述的权限太低,至少需要65536;
解决办法:
#切换到root用户修改
vim /etc/security/limits.conf
在最后面追加下面内容
*** hard nofile 65536
*** soft nofile 65536
*** 是启动ES的用户
使用sysctl -p刷新配置文件
切换用户使用 ulimit -Hn 查看当前值 是65535就成功
10、虚拟内存区域限制太低问题(vm.max_map_count [65530] is too low,crease to at 262144)
elasticsearch用户拥有的内存权限太小,至少需要262144,解决办法:
在 /etc/sysctl.conf 文件最后添加如下内容,即可永久修改
- 切换到root用户
执行命令:su root
- 执行命令
vim /etc/sysctl.conf
- 添加如下内容
vm.max_map_count=262144
- 保存退出,刷新配置文件
sysctl -p
- 切换user-es用户,继续启动
su user-es
- 启动es服务
./bin/elasticsearch -d
11、开放http访问
使用vim编辑config目录下的elasticsearch.yml文件
将xpack.security.enabled: true
和xpack.security.transport.ssl: enabled: true
修改为false
network.host: 0.0.0.0 http.port: 9200 ingest.geoip.downloader.enabled: false # Enable security features xpack.security.enabled: false xpack.security.enrollment.enabled: true # Enable encryption for HTTP API client connections, such as Kibana, Logstash, and Agents xpack.security.http.ssl: enabled: true keystore.path: certs/http.p12 # Enable encryption and mutual authentication between cluster nodes xpack.security.transport.ssl: enabled: false verification_mode: certificate keystore.path: certs/transport.p12 truststore.path: certs/transport.p12
5、安装kibana
1、下载与es版本相同的kibana的tar.gz
2、解压到自己需要的目录
此处我解压到了es的同级目录:
tar -zxvf kibana-8.1.2-linux-x86_64.tar.gz -C /usr/local/
3、权限配置: 设置对安装目录下文件的拥有权限:
chown -R user-es:user-es kibana-8.1.2
4、修改配置:
vim /usr/local/kibana-8.1.2/config/kibana.yml
通过指令打开kibana的yml文件,修改以下配置
#修改主机地址设为本地,设置本机可以访问 server.host: "0.0.0.0" #配置ES的IP地址,有需要可修改 #elasticsearch.hosts: ["http://localhost:9200"]
5、启动命令(要提前启动ES):
切换到user-es用户,进入kibana的bin目录
./kibana 后台启动 nohup ./kibana &
6、地址栏访问 服务器地址:5601
http://172.18.22.129:5601
kibana初始化与Es链接SSl的token 有效期30分钟
过期使用.\elasticsearch-create-enrollment-token -s kibana
再次创建
将生成的token 复制进来
点击Configure Elastic等待片刻
进入页面
输入elasticSearch的账号密码登录
elastic
elastic
7、汉化
在config/kibana.yml中添加下行重启即可
i18n.locale: "zh-CN"
8、停止命令、后台启动
切换到user-es用户
nohup ./kibana & 或者 nohup ./kibana >/dev/null & - 查看进程号 jps 或者 ps -ef|grep kibana 或者 ps -ef|grep 5601 - 杀死进程 kill -9 进程号 netstat -tunlp | grep 5601 // 可用
21811就是进程号
9、修改es为http访问后,kibana无法访问的问题
编辑kibana.yml文件,将https改为http。重启kibana即可。
2024-9-23更新:修改es地址从172.17.0.1集群网段修改为为localhost
6、安装ik分词器
1、下载与es版本相同的ik压缩包 elasticsearch-analysis-ik-8.1.2.zip
2、上传并解压
在elasticsearch-8.1.2/plugins目录下创建ik分词器文件夹(文件夹名称一定要为ik,不然启动elasticsearch报错)
在plugins目录创建文件夹命令如下:
mkdir ik
再将ik安装包传输到ik文件夹中解压,或直接解压后再上传:
tar -zxvf analysis-ik-8.1.2.tar.gz
上传完毕后重启es即可使用,使用示例
POST _analyze { "analyzer":"ik_smart", "text": ["我是中国人!"] }
POST _analyze { "analyzer":"ik_max_word", "text": ["我是中国人!"] }
ik分词器不会跟ElasticSearch标准分词器一样只会把每个汉字拆分为单独一个词项,而是会根据分词类型(ik_smart,ik_max_word)把汉字拆分为不同词项,而且ik_smart拆分颗粒度比较粗糙,ik_max_word拆分颗粒度比较细致。
在建索引的时候使用 ik_max_word 分词器,这样分的词可以更细。
在搜索的时候使用 ik_smart 分词器,这样在搜索的时候分的词粒度更粗,只用查更少的词,能提高效率。
- ik分词器支持扩展词典
- IK分词器支持热词更新
7、在项目使用ElasticSearch
导入依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency> <dependency> <groupId>co.elastic.clients</groupId> <artifactId>elasticsearch-java</artifactId> <version>8.1.2</version> </dependency>
nacos中的配置
# elasticsearch配置 elasticsearch: host: localhost port: 9200 scheme: http
ElasticSearchConfig.java
import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import co.elastic.clients.elasticsearch.ElasticsearchClient; import co.elastic.clients.transport.rest_client.RestClientTransport; import co.elastic.clients.transport.ElasticsearchTransport; import co.elastic.clients.json.jackson.JacksonJsonpMapper; import org.elasticsearch.client.RestClient; import org.apache.http.HttpHost; @Configuration public class ElasticSearchConfig { @Value("${elasticsearch.host}") private String host; @Value("${elasticsearch.port}") private int port; @Value("${elasticsearch.scheme}") private String scheme; @Bean public ElasticsearchClient elasticsearchClient() { RestClient client = RestClient.builder(new HttpHost(host, port, scheme)).build(); ElasticsearchTransport transport = new RestClientTransport(client, new JacksonJsonpMapper()); return new ElasticsearchClient(transport); } }
FileSearch.java
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Data; @Data @JsonIgnoreProperties(ignoreUnknown = true) public class FileSearch { private String indexName; private String userFileId; private String fileId; private String fileName; private String content; private String fileUrl; private Long fileSize; private Integer storageType; private String identifier; private Long userId; private String filePath; private String extendName; private Integer isDir; private String uploadTime; private Integer deleteFlag; private String deleteTime; private String deleteBatchNum; }
然后在文件上传和删除的时候更新ES的索引即可。
public void uploadESByUserFileId(String userFileId) { exec.execute(()->{ try { Map<String, Object> param = new HashMap<>(); param.put("userFileId", userFileId); List<UserFile> userfileResult = userFileMapper.selectByMap(param); if (userfileResult != null && userfileResult.size() > 0) { FileSearch fileSearch = new FileSearch(); BeanUtil.copyProperties(userfileResult.get(0), fileSearch); elasticsearchClient.index(i -> i.index("filesearch").id(fileSearch.getUserFileId()).document(fileSearch)); } } catch (Exception e) { log.debug("ES更新操作失败,请检查配置"); } }); } public void deleteESByUserFileId(String userFileId) { exec.execute(() -> { try { elasticsearchClient.delete(d -> d .index("filesearch") .id(userFileId)); } catch (Exception e) { log.debug("ES删除操作失败,请检查配置"); } }); }