文章目录
为什么要用
安装
安装es
- java需要java环境(es7自带),关闭防火墙
sudo systemctl stop firewalld
- 创建用户设置密码,es不允许root用户启动
useradd es
,passwd es
- 切换到es用户
su es && cd /home/es
- 下载
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.17.2-linux-x86_64.tar.gz
- 解压
tar -zxvf elasticsearch-7.17.2-linux-x86_64.tar.gz && cd elasticsearch-7.17.2
- 修改两处配置项(方便在主机访问,不改也能启动):
vi config/elasticsearch.yml``network.host: 0.0.0.0``discovery.seed_hosts: ["10.211.55.26"]
- 启动
nohup ./bin/elasticsearch &
,curl -v 127.0.0.1:9200
返回 - 启动可能遇到的问题
max file descriptors [4096] for elasticsearch process likely too low, increase to at least [65536]
设置最大打开句柄和允许生成的线程数- 解决方案:
sudo vi /etc/security/limits.conf
重新登陆 查看是否生效# soft警告值,hard最大值,nproc创建线程数量,nofile 每个进程打开的文件数量限制 * soft nofile 65536 * hard nofile 13107
ulimit -H -n
- 解决方案:
max number of threads [1024] for user [es] likely too low, increase to at least [4096]
普通用户可以创建的最大线程数- 解决方案:
sudo vi /etc/security/limits.d/20-nproc.conf
* soft nproc 4096
- 解决方案:
max virtual memory areas vm.max_map_count [65530] likely too low, increase to at least [262144]
- 解决方案:
sudo vim /etc/sysctl.conf
vm.max_map_count=262144
- 解决方案:
安装图形化界面kibana
- 下载
https://artifacts.elastic.co/downloads/kibana/kibana-7.17.2-darwin-x86_64.tar.gz
- 解压
tar -zxvf kibana-7.17.2-darwin-x86_64.tar.gz
- 配置
vi kibana-7.17.2-darwin-x86_64/config/kibana.yml ``server.host: "10.211.55.26"``elasticsearch.hosts: ["http://10.211.55.26:9200"]
- 访问http://10.211.55.26:5601
安装中文分词器
- 根据安装的es版本进行下载
https://github.com/medcl/elasticsearch-analysis-ik/releases
- 解压zip包
unzip elasticsearch-analysis-ik-7.17.2.zip -d elasticsearch-7.17.2/plugins/ik
- 重启es
安装elasticsearch-head
- 主机有nodejs环境
- 下载源代码
git clone https://github.com/mobz/elasticsearch-head.git && cd elasticsearch-head
- 安装依赖
npm install
- 修改配置
vi _site/app.js
- 启动
npm run start
- 浏览器访问
http://10.211.55.26:9100/
- 使用,支持查询索引分片集群健康情况,普通搜索和dsl查询
数据管理
- index,type,document,field
关系型数据库 | database | table | row | column |
---|---|---|---|---|
es | index | type | docment | field |
- 基础操作
- 操作索引
- 创建索引官网介绍
PUT /test { "settings": { // 指定分片_cat/indices?v查看分片副本状态 "number_of_shards": 5, // 指定副本 每个分片的副本数 "number_of_replicas": 1 }, // 起别名 多对多,写入只能有一个 "aliases": { "testName": {} }, //指定每个field的数据结构,es6可以指定type es7默认_doc "mappings": { "properties": { "name": { "type": "text" }, "age": { "type": "short" } } } }
- 查询索引
//使用索引名称或别名 GET /testName GET /test
- 删除索引
// 删除索引 使用索引名称或别名 DELETE /test DELETE /testName
- 操作文档
- 添加或修改
// index/type/id PUT /test/_doc/1
- 查询文档
get /test/_doc/1
- 删除文档
delete /test/_doc/1
- 文档查询
- 查询type中所有文档
get /test/_doc/_search
- 等值查询
get /index/type/_search?q=field:value
- 范围查询:
get /test/_doc/_search?q=age[12 TO 14]``get /test/_doc/_search?q=age:<=12
- 多id查询
get /test/_doc/_mget { "ids":["1","2"] }
- 分页查询跳过多少数据返回多少数据
get /test/_doc/_search?from=1&size=2
- 指定返回的字段
get /test/_doc/_search?_source=name,age
- 字段排序:
get /test/_doc/_search?sort=age:asc
- 查询type中所有文档
- 操作索引
- _mget使用
get /test/_doc/_mget
{
"docs": [
{
//index,id必填index,type可在url中
"_index": "test",
"_type": "_doc",
"_id": "1",
"_source":["name","age"]
}
]
}
- _buik使用,上一行为操作对象与操作,下一行为参数
POST _bulk
{"create": {"_index": "test","_type": "_doc"}}
{"name": "test1"}
{"create": {"_index": "test","_type": "_doc","_id":"6"}}
{"name": "test1"}
{"update":{"_index":"test","_type":"_doc","_id":"5"}}
{"doc":{"name":"test2"}}
{"index":{"_index":"test","_type":"_doc","_id":"5"}}
{"name":"test3"}
{"delete":{"_index":"test","_type":"_doc","_id":"6"}}
- dsl语法:文档入es进行分词,这里的查询都是对分词后的关键词进行查询,官方文档
- 无条件查询
GET /test/_search { "query": { "match_all": {} } }
- 模糊查询与精准查询
- match
GET /test/_search { //select * from test_name_keyword where keyword ='河' or keyword='南' 对test索引中的name字段的关键词进行搜索,这里会对查询结果也进行分词 "query": { "match": { //默认为or "name": "河南" } } }
GET /test/_search { "query": { //select * from test_name_keyword where keyword ='河' and keyword='南' "match": { "name": { "query": "河南", "operator": "and" } } } }
- prefix
GET /test/_search { //select * from test_name_keyword where keyword like '北%' 这里不会对查询的参数也进行分词 "query": { "prefix": { //默认为or "name": "北" } } }
- regexp
GET /test/_search { "query": { //select * from test_name_keyword where keyword regexp '河|南' "regexp": { "name":"河|南" } } }
- term
GET /test/_search { "query": { //select * from test_name_keyword where keyword = '河南' 不会对搜索参数进行分词 "term": { "name":"河南" } } }
- terms
GET /test/_search { //select * from test_name_keyword where keyword ='hello' or keyword ='world' 这里不会对查询的参数也进行分词 "query": { "terms": { "name": ["hello","world"] } } }
- 范围查询 gte大于等于,lte小于等于,gt大于,lt小于
GET /test/_search { "query": { "range": { "age": { "gte": 10, "lte": 20 } } } }
- exists:
GET /test/_search { //返回含有name字段的文档 "query": { "exists": { "field": "name" } } }
- ids
GET /test/_search { "query": { "ids": { "values": [ "PqIRN4ABbtnWqjekU16e" ] } } }
- query_string:和match类似不用指定字段名称
- match_phase: 会对参数分词但必须包含所有分词且顺序固定
GET /test/_search { "query": { "match_phrase": { "name": "hello world" } } }
- match
- 多条件
- bool:
- must:必须符合条件,里面的关系是and
- should:or
- must not 不能有,不计分会缓存
- filter: 和must一样,and关系,不计分会缓存
GET /test/_search { "query": { "bool": { "filter": [ { "term": { "name": "hello" } } ], "must_not": [ { "range": { "age": { "gt": 15 } } }] } } }
- constant_score恒分查询:直接修改查询结果的分
GET /test/_search { "query": { "constant_score": { "filter": { "term": { "name": "hello" } }, "boost": 0.1 } } }
- bool:
- 基础类型
- 字符串:text和keyword
- 区别:text会被分词不能用来排序和聚合,keyword不会被分词可以用来过滤排序聚合
- 数值: long,integer,short,byte,double,float
- 日期:date
- 布尔:boolean
- 字符串:text和keyword
- 动态映射与静态映射
- 动态映射:不需要指定指定字段名称与类型,插入第一条数据时自定映射
- 静态映射:事先指定好字段名称与类型,分词器,后续为指定的字段还是会动态映射
- 修改mapping:新建一个,老的传过去,删除老的,新的起个别名
PUT /test1
{
"mappings": {
"properties": {
"name": {
"type": "text",
"analyzer": "ik_max_word"
},
"age": {
"type": "text",
"index": false
}
}
}
}
POST _reindex
{
"source": {
"index": "test"
},
"dest": {
"index": "test1"
}
}
DELETE test
PUT /test1/_alias/test
集群
#保持一致 默认elasticsearch
#cluster.name: my-application
#每个节点名称不同
node.name: node1
network.host: 0.0.0.0
# 上下保持顺序
discovery.seed_hosts: ["10.211.55.26","10.211.55.29"]
cluster.initial_master_nodes: ["node1", "node2"]
查询集群状态
GET _cat/health?v
GET _cat/nodes?v
es乐观并发控制
POST /test/_doc/1/?if_primary_term=1&if_seq_no=3
{
"name":"test",
"age":1
}
es架构
- 节点类型
- master节点:es启动后会通过Zen Discovery机制找到集群中的其他节点并建立连接,并从候选主节点中选举出一个主节点,master节点主要负责管理索引(创建删除索引),分配分片,维护元数据,管理集群节点状态,不负责数据写入和查询
- datanode:数据写入查询
重要工作流程
写入流程
- 每个节点都是协调节点,根据文档的id计算路由到哪个分片,算法默认是文档id%分片数
- 主分片写入,写入完成后副本写入,逐级返回结构
- 具体详细过程可参考ElasticSearch写入流程详解,深入理解Elasticsearch写入过程
检索流程
- 每个节点都是协调节点,收到请求后将查询请求广播到各个数据节点
- 每个数据节点进行查询,将符合条件的数据放在一个优先队列,将这些数据的文档id,节点信息,分片信息返回给协调节点
- 协调节点将结果进行汇总,排序,分页等
- 协调节点想包含这些文档id的分片发送get请求,对应的分片将数据返回给协调节点
- 协调节点进行返回给客户端
准实时索引实现
当数据写入到es的分片中时会首先写入到memory buffer中,同时会记录translog,将memory buffer的数据每1秒钟刷新到File system cache,删除memory buffer,每30分钟同步到磁盘中删除
java api使用
// <dependency>-->
// <groupId>org.elasticsearch.client</groupId>-->
// <artifactId>elasticsearch-rest-high-level-client</artifactId>-->
// <version>7.17.2</version>-->
// </dependency>
// RestClientBuilder restClientBuilder = RestClient.builder(new HttpHost("10.211.55.26", 9200, "http"),
// new HttpHost("10.211.55.29", 9200, "http"),
// new HttpHost("10.211.55.30", 9200, "http"));
// RestHighLevelClient restHighLevelClient = new RestHighLevelClient(restClientBuilder);
// IndexRequest indexRequest = new IndexRequest("user");
// User user = new User();
// user.setUserId("1");
// user.setUserName("测试");
// user.setAge(1);
// indexRequest.id(user.getUserId());
// indexRequest.source(JSON.toJSONString(user), XContentType.JSON);
// IndexResponse indexResponse = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
// System.out.println(indexResponse.getResult());
// <dependency>
// <groupId>co.elastic.clients</groupId>
// <artifactId>elasticsearch-java</artifactId>
// <version>7.17.2</version>
// </dependency>
RestClient restClient = RestClient.builder(new HttpHost("10.211.55.26", 9200, "http"),
new HttpHost("10.211.55.29", 9200, "http"),
new HttpHost("10.211.55.30", 9200, "http")).build();
RestClientTransport restClientTransport = new RestClientTransport(restClient, new JacksonJsonpMapper());
ElasticsearchClient elasticsearchClient = new ElasticsearchClient(restClientTransport);
//创建索引
// CreateIndexResponse createIndexResponse = elasticsearchClient.indices().create(builder -> builder.index("user"));
// 插入doc
// Map<String, Object> map = new HashMap<>();
// map.put("userName", "test");
// map.put("age", "12");
// map.put("id", 1);
// elasticsearchClient.create(CreateRequest.of(e -> e.index("user").id("1").document(map)));
SearchRequest searchRequest = SearchRequest.of(builder -> builder.index("user").query(builder1 -> builder1.term(builder2 -> builder2.field("userName").value("test"))));
SearchResponse<Object> search = elasticsearchClient.search(searchRequest, Object.class);
ArrayList<Object> objects = new ArrayList<>();
if (search.hits() != null) {
List<Hit<Object>> list = search.hits().hits();
for (Hit<Object> hit :
list) {
Object t = (Object) hit.source();
objects.add(t);
}
}
System.out.println(objects);
}