docker 搭建ES集群
关闭防火墙设置底层系统参数准备网络和 挂载目录启动3个集群查看结果查看节点浏览器插件 基础用法
倒排索引分词方式
ngram_analyzerCJKIK
安装IK分词器分词方式
ik_smartik_max_word kibana
下载镜像启动容器 索引 分片 副本
创建索引 映射(数据结构)
常用数据类型创建映射添加数据查看文档
查看指定文档title字段的分词结果 修改文档删除清空删除索引 搜索
添加数据
创建索引和映射导入数据 搜索数据
搜索所有数据搜索关键字过滤数据搜索结果高亮显示 Spring Data Elasticsearch API
配置文件基础操作定义接口方法名对查询结果进行分页
分页工具
docker 搭建ES集群 关闭防火墙# 关闭防火墙 systemctl stop firewalld.service # 禁用防火墙 systemctl disable firewalld.service设置底层系统参数
echo 'vm.max_map_count=262144' >>/etc/sysctl.conf准备网络和 挂载目录
# 创建虚拟网络 docker network create es-net # node1 的挂载目录 mkdir -p -m 777 /var/lib/es/node1/plugins mkdir -p -m 777 /var/lib/es/node1/data # node2 的挂载目录 mkdir -p -m 777 /var/lib/es/node2/plugins mkdir -p -m 777 /var/lib/es/node2/data # node3 的挂载目录 mkdir -p -m 777 /var/lib/es/node3/plugins mkdir -p -m 777 /var/lib/es/node3/data启动3个集群
参数解释
docker run -d --name=node1 --restart=always # 连接虚拟网络 --net es-net # 端口映射 9200 和客户端通信 -p 9200:9200 # 9300 集群服务器之间通信 -p 9300:9300 # 插件安装目录 -v /var/lib/es/node1/plugins:/usr/share/elasticsearch/plugins # 数据存储目录 -v /var/lib/es/node1/data:/usr/share/elasticsearch/data # 唯一的节点名 -e node.name=node1 # 是否可被选为主节点 -e node.master=true # 当前节点的地址 -e network.host=node1 # 集群中其他节点的地址列表 -e discovery.seed_hosts=node1,node2,node3 # 候选的主节点地址列表 -e cluster.initial_master_nodes=node1 # 集群名 同一集群名字需一致 -e cluster.name=es-cluster # 内存大小 -e "ES_JAVA_OPTS=-Xms256m -Xmx256m" # 镜像 elasticsearch:7.9.3
node1:
docker run -d --name=node1 --restart=always --net es-net -p 9200:9200 -p 9300:9300 -v /var/lib/es/node1/plugins:/usr/share/elasticsearch/plugins -v /var/lib/es/node1/data:/usr/share/elasticsearch/data -e node.name=node1 -e node.master=true -e network.host=node1 -e discovery.seed_hosts=node1,node2,node3 -e cluster.initial_master_nodes=node1 -e cluster.name=es-cluster -e "ES_JAVA_OPTS=-Xms256m -Xmx256m" elasticsearch:7.9.3
node2:
docker run -d --name=node2 --restart=always --net es-net -p 9201:9200 -p 9301:9300 -v /var/lib/es/node2/plugins:/usr/share/elasticsearch/plugins -v /var/lib/es/node2/data:/usr/share/elasticsearch/data -e node.name=node2 -e node.master=true -e network.host=node2 -e discovery.seed_hosts=node1,node2,node3 -e cluster.initial_master_nodes=node1 -e cluster.name=es-cluster -e "ES_JAVA_OPTS=-Xms256m -Xmx256m" elasticsearch:7.9.3
node3:
docker run -d --name=node3 --restart=always --net es-net -p 9202:9200 -p 9302:9300 -v /var/lib/es/node3/plugins:/usr/share/elasticsearch/plugins -v /var/lib/es/node3/data:/usr/share/elasticsearch/data -e node.name=node3 -e node.master=true -e network.host=node3 -e discovery.seed_hosts=node1,node2,node3 -e cluster.initial_master_nodes=node1 -e cluster.name=es-cluster -e "ES_JAVA_OPTS=-Xms256m -Xmx256m" elasticsearch:7.9.3查看结果
http://192.168.64.181:9200/
查看节点http://192.168.64.181:9200/_cat/nodes
浏览器插件在 elasticsearch-head 项目仓库中下载 chrome 浏览器插件
https://github.com/mobz/elasticsearch-head/raw/master/crx/es-head.crx
将文件后缀改为 zip
解压缩
在 chrome 浏览器中选择“更多工具”–“扩展程序”
在“扩展程序”中确认开启了“开发者模式”
点击“加载已解压的扩展程序”
选择前面解压的插件目录
在浏览器中点击 elasticsearch-head 插件打开 head 界面,并连接 http://192.168.64.181:9200/
是一种数据库,搜索引擎,会将文档进行分词,所以查询效率较高
倒排索引将分词后的关键词与包含关键词的文档进行对应关联
分词方式 ngram_analyzer更适用于人名
CJK两个字两个字进行分词(不太好)
IKIK 有字典库,他会将文档中的字与字典库进行比对
安装IK分词器需要和 IK 和 Elasticsearch版本一致
- 复制 ik 分词器到三个 es 容器
docker cp elasticsearch-analysis-ik-7.9.3.zip node1:/root/ docker cp elasticsearch-analysis-ik-7.9.3.zip node2:/root/ docker cp elasticsearch-analysis-ik-7.9.3.zip node3:/root/
- 分别在容器中安装插件
# 在 node1 中安装 ik 分词器 docker exec -it node1 elasticsearch-plugin install file:///root/elasticsearch-analysis-ik-7.9.3.zip
# 在 node2 中安装 ik 分词器 docker exec -it node2 elasticsearch-plugin install file:///root/elasticsearch-analysis-ik-7.9.3.zip
# 在 node3 中安装 ik 分词器 docker exec -it node3 elasticsearch-plugin install file:///root/elasticsearch-analysis-ik-7.9.3.zip
- 重启
# 重启三个 es 容器 docker restart node1 node2 node3分词方式 ik_smart
粗粒度的拆分
向 http://192.168.64.181:9200/_analyze 路径提交 POST 请求
最细粒度的拆分,会穷尽各种可能的组合
向 http://192.168.64.181:9200/_analyze 路径提交 POST 请求
docker pull kibana:7.9.3启动容器
docker run -d --name kibana --net es-net -p 5601:5601 -e ELASTICSEARCH_HOSTS='["http://node1:9200","http://node2:9200","http://node3:9200"]' --restart=always kibana:7.9.3
输入网址访问http://192.168.64.181:5601/
索引 分片 副本可以将索引分片存在多台服务器上,提高搜索效率(分布式搜索)
防止服务器关闭创建副本
主服务器负责分发,结果汇总
创建索引number_of_shards:分片的数量,默认5
number_of_replicas: 副本的数量,默认1
# 创建索引,命名为 products
PUT /products
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 2
}
}
粗框表示主分片,细框表示副本分片
类似于数据库表结构,索引数据也被分为多个数据字段,并且需要设置数据类型和其他属性。
映射,是对索引中字段结构的定义和描述。
常用数据类型数字类型
byte、short、integer、longfloat、doubleunsigned_long 字符串类型
text : 会进行分词keyword : 不会进行分词,适用于email、主机地址、邮编等 日期时间类型
date 创建映射
analyzer:在索引中添加文档时,text类型通过指定的分词器分词后,再插入倒排索引
search_analyzer:使用关键词检索时,使用指定的分词器对关键词进行分词
# 定义mapping,数据结构
PUT /products/_mapping
{
"properties": {
"id": {
"type": "long"
},
"title": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
},
"category": {
"type": "text",
"analyzer": "ik_smart",
"search_analyzer": "ik_smart"
},
"price": {
"type": "float"
},
"city": {
"type": "text",
"analyzer": "ik_smart",
"search_analyzer": "ik_smart"
},
"barcode": {
"type": "keyword"
}
}
}
查看映射
GET /products/_mapping添加数据
添加的文档会有一个名为_id的文档id,这个文档id可以自动生成,也可以手动指定,通常可以使用数据的id作为文档id
# 添加文档
PUT /products/_doc/10033
{
"id":"10033",
"title":"SonOS PLAY:5(gen2) 新一代PLAY:5无线智能音响系统 WiFi音箱家庭,潮酷数码会场",
"category":"潮酷数码会场",
"price":"3980.01",
"city":"上海",
"barcode":"527848718459"
}
PUT /products/_doc/10034
{
"id":"10034",
"title":"天猫魔盒 M13网络电视机顶盒 高清电视盒子wifi 64位硬盘播放器",
"category":"潮酷数码会场",
"price":"398.00",
"city":"浙江杭州",
"barcode":"522994634119"
}
PUT /products/_doc/10035
{
"id":"10035",
"title":"BOSE SoundSport耳塞式运动耳机 重低音入耳式防脱降噪音乐耳机",
"category":"潮酷数码会场",
"price":"860.00",
"city":"浙江杭州",
"barcode":"526558749068"
}
PUT /products/_doc/10036
{
"id":"10036",
"title":"【送支架】Beats studio Wireless 2.0无线蓝牙录音师头戴式耳机",
"category":"潮酷数码会场",
"price":"2889.00",
"city":"上海",
"barcode":"37147009748"
}
PUT /products/_doc/10037
{
"id":"10037",
"title":"SonOS PLAY:1无线智能音响系统 美国原创WiFi连接 家庭桌面音箱",
"category":"潮酷数码会场",
"price":"1580.01",
"city":"上海",
"barcode":"527783392239"
}
查看文档
GET /products/_doc/10037查看指定文档title字段的分词结果
GET /products/_doc/10035/_termvectors?fields=city修改文档
底层索引数据无法修改,修改数据实际上是先删除再重新添加。
两种修改方式:
底层都是先删除后添加
PUT:对文档进行完整的替换
需完整的文档数据
# 修改文档 - 替换
PUT /products/_doc/10037
{
"id":"10037",
"title":"SonOS PLAY:1无线智能音响系统 美国原创WiFi连接 家庭桌面音箱",
"category":"潮酷数码会场",
"price":"9999.99",
"city":"上海",
"barcode":"527783392239"
}
POST:可以修改一部分字段
# 修改文档 - 更新部分字段
POST /products/_update/10037
{
"doc": {
"price":"8888.88",
"city":"深圳"
}
}
删除
DELETE /products/_doc/10037清空
POST /products/_delete_by_query
{
"query": {
"match_all": {}
}
}
删除索引
# 删除 products 索引 DELETE /products搜索 添加数据 创建索引和映射
PUT /pditems
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 2
},
"mappings": {
"properties": {
"id": {
"type": "long"
},
"brand": {
"type": "text",
"analyzer": "ik_smart"
},
"title": {
"type": "text",
"analyzer": "ik_max_word"
},
"sell_point": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
},
"price": {
"type": "float"
},
"image": {
"type": "keyword"
},
"cid": {
"type": "long"
},
"status": {
"type": "byte"
},
"created": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss"
},
"updated": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss"
}
}
}
}
导入数据
curl -XPOST 'localhost:9200/pditems/_bulk'
-H 'Content-Type:application/json'
--data-binary @pditems.json
搜索数据
搜索所有数据
# 搜索 pditems 索引中全部数据
POST /pditems/_search
{
"query": {
"match_all": {}
}
}
搜索关键字
# 查询 pditems 索引中title中包含"电脑"的商品
POST /pditems/_search
{
"query": {
"match": {
"title": "电脑"
}
}
}
过滤数据
# 价格大于2000,并且title中包含"电脑"的商品
POST /pditems/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"title": "电脑"
}
}
],
"filter": [
{
"range": {
"price": {
"gte": "2000"
}
}
}
]
}
}
}
搜索结果高亮显示
multi_match:多个字段
POST /pditems/_search
{
"query": {
"multi_match":{
"query": "手机",
"fields": ["title", "sell_point"]
}
},
"highlight" : {
"pre_tags" : [""],
"post_tags" : [""],
"fields" : {
"title" : {},
"sell_point" : {
"pre_tags": "",
"post_tags": ""
}
}
}
}
Spring Data Elasticsearch API
配置文件
spring:
elasticsearch:
rest:
uris:
- http://192.168.64.181:9200
- http://192.168.64.181:9201
- http://192.168.64.181:9202
logging:
level:
# 通信数据日志
tracer: TRACE
基础操作
package cn.tedu.es;
import cn.tedu.entity.Student;
import cn.tedu.repo.StudentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Optional;
@SpringBootTest
public class Test {
@Autowired
private StudentRepository studentRepository;
// 添加数据,修改也是用save方法
@org.junit.jupiter.api.Test
public void test1() {
Student s1 = new Student(9527L, "安妮", '女', "1997-10-19");
Student s2 = new Student(9528L, "发条", '女', "1998-10-19");
Student s3 = new Student(9529L, "龙王", '男', "1996-10-19");
Student s4 = new Student(9526L, "龙女", '女', "1999-10-19");
Student s5 = new Student(9525L, "卡牌", '男', "1995-10-19");
Student s6 = new Student(9524L, "安妮", '女', "1994-10-19");
Student s7 = new Student(9523L, "亚索", '男', "1993-10-19");
studentRepository.save(s1);
studentRepository.save(s2);
studentRepository.save(s3);
studentRepository.save(s4);
studentRepository.save(s5);
studentRepository.save(s6);
studentRepository.save(s7);
}
//查询数据
@org.junit.jupiter.api.Test
public void test3() {
// Optional // 避免空指针异常的工具类
Optional op = studentRepository.findById(9527L);
if (op.isPresent()) { // 检查内存包含的学生对象是否存在
Student student = op.get();
System.out.println(student);
}
System.out.println("-----------------------------");
// 查询所有学生
Iterable iterable = studentRepository.findAll();
for (Student student : iterable) {
System.out.println(student);
}
}
// 删除数据
@org.junit.jupiter.api.Test
public void test4() {
studentRepository.deleteById(9526L);
}
}
定义接口方法名
按照Repository规范对方法名命名就可以进行相应的查询
package cn.tedu.repo; import cn.tedu.entity.Student; import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; import org.yaml.snakeyaml.events.Event; import java.util.List; public interface StudentRepository extends ElasticsearchRepository对查询结果进行分页 分页工具{ // 按照Repository规范对方法名命名就可以进行相应的查询 // 按照名字查询 List findByName(String k); // 按名字或生日查询 List findByNameOrBirthDate(String name, String birthDate); }
Pageble: 封装向服务器提交的分页参数,页号,每页大小Page: (可选)封装服务器返回的搜索结果页面,这一页数据,分页参数属性
接口中的内容
// 按名字或生日查询
Page findByNameOrBirthDate(String name, String birthDate, Pageable pageable);
查询方法
public void test5(){
Pageable p = PageRequest.of(0, 2);// 0 表示第几页 2:表示每页几条
Page list = studentRepository.findByNameOrBirthDate("龙", "1997-10-09", p);
System.out.println(list);
// 是否有下一页
System.out.println(list.hasNext());
// 是否有上一页
System.out.println(list.hasPrevious());
// 数据量
System.out.println(list.getTotalElements());
// 共有多少页
System.out.println(list.getContent());
}



