Java零基础——Elasticsearch篇

1.Elasticsearch简介

Elasticsearch是一个基于Lucene的一个开源的分布式、RESTful 风格的搜索和数据分析引擎。Elasticsearch是用Java语言开发的,并作为Apache许可条款下的开放源码发布,是一种流行的企业级搜索引擎。Elasticsearch用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。官方客户端在Java、.NET(C#)、PHP、Python、Apache Groovy、Ruby和许多其他语言中都是可用的。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr,也是基于Lucene。

2.Lucene 核心库(红黑二叉树)

Lucene 可以说是当下最先进、高性能、全功能的搜索引擎库——无论是开源还是私有,但它也仅仅只是一个库。为了充分发挥其功能,你需要使用 Java 并将 Lucene 直接集成到应用程序中。 更糟糕的是,您可能需要获得信息检索学位才能了解其工作原理,因为Lucene 非常复杂。

为了解决Lucene使用时的繁复性,于是Elasticsearch便应运而生。它使用 Java 编写,内部采用 Lucene 做索引与搜索,但是它的目标是使全文检索变得更简单,简单来说,就是对Lucene 做了一层封装,它提供了一套简单一致的 RESTful API 来帮助我们实现存储和检索。
在这里插入图片描述

3.和solr对比

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

ElasticSearch 对比 Solr 总结

  1. es基本是开箱即用,非常简单。Solr安装略微复杂一丢丢

  2. Solr 利用 Zookeeper 进行分布式管理,而 Elasticsearch 自身带有分布式协调管理功能。

  3. Solr 支持更多格式的数据,比如JSON、XML、CSV,而 Elasticsearch 仅支持json文件格式。

  4. Solr 官方提供的功能更多,而 Elasticsearch 本身更注重于核心功能,高级功能多有第三方插件提供,例如图形化界面需要kibana,head等友好支撑,分词插件

  5. Solr 查询快,但更新索引时慢(即插入删除慢),用于电商等查询多的应用(之前);

ES建立索引快(即查询慢),即实时性查询快,用于推特 新浪等搜索。

Solr 是传统搜索应用的有力解决方案,但 Elasticsearch 更适用于新兴的实时搜索应用。

  1. Solr比较成熟,有一个更大,更成熟的用户、开发和贡献者社区,而 Elasticsearch相对开发维护者较少,更新太快,学习使用成本较高。 (现在es也比较火)

4.倒排索引(重点)

正排索引根据id 找到对应的一组数据 (B+tree 聚簇索引)

非聚簇索引:给一个字段建立索引,查询的时候 根据这个字段查到这行数据对应的id

回表 再根据id 去查 聚簇索引 从而拿到一行数据

4.1 正排索引
在这里插入图片描述

4.2 倒排索引
在这里插入图片描述

一个倒排索引由文档中所有不重复词的列表构成,对于其中每个词,有一个包含它的 Term 列表。

5.分词

就是按照一定的规则,将一句话分成组合的单词,按照国人喜欢来进行的

海上生明月 - 如何分成 ----->海上 | 生 | 明月

我想要个女朋友 ---- > 我|想要|要个|女朋友|朋友

6.模拟一个倒排索引

原理步骤:

  1. 将数据存入mysql之前,对其进行分词

  2. 讲分词和存入后得到的id,存放在数据结构中Map<String,Set> index

  3. 查询时先分词,然后从index中拿到Set ids

  4. 再根据ids 查询mysql,从而得到结果,这样借助了mysql的B+tree索引,提高性能

6.1 创建boot项目选择依赖
在这里插入图片描述

6.2 引入分词的依赖

<dependency><groupId>com.huaban</groupId><artifactId>jieba-analysis</artifactId><version>1.0.2</version>
</dependency>

6.3 修改启动类,注入结巴分词器

/*** 往IOC容器中入住结巴分词组件** @return*/
@Bean
public JiebaSegmenter jiebaSegmenter() {return new JiebaSegmenter();
}

6.4 测试分词

@Autowired
public JiebaSegmenter jiebaSegmenter;@Test
void testJieBa() {String words = "华为 HUAWEI P40 Pro 麒麟990 5G SoC芯片 5000万超感知徕卡四摄 50倍数字变焦 8GB+256GB零度白全网通5G手机";// 使用结巴分词,对字符串进行分词,分词类型为搜索类型List<SegToken> tokens = jiebaSegmenter.process(words, JiebaSegmenter.SegMode.INDEX);// 遍历,拿到SegToken对象中的word属性,打印结果tokens.stream().map(token -> token.word).collect(Collectors.toList()).forEach(System.out::println);
}

6.5 使用商品搜索案例来展示倒排索引结构

6.5.1 新建Goods类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Goods {/*** 商品的id*/private Integer goodsId;/*** 商品的名称(主要分词和检索字段)*/private String goodsName;/*** 商品的价格*/private Double goodsPrice;}

6.5.2 模拟数据库,新建DBUtil类

public class DBUtil {/*** 模拟数据库,key=id,value=商品对象* 这里也可以使用List来模拟*/public static Map<Integer, Goods> db = new HashMap<>();/*** 插入数据库** @param goods*/public static void insert(Goods goods) {db.put(goods.getGoodsId(), goods);}/*** 根据id得到商品** @param id* @return*/public static Goods getGoodsById(Integer id) {return db.get(id);}/*** 根据ids查询商品集合** @param ids* @return*/public static List<Goods> getGoodsByIds(Set<Integer> ids) {if (CollectionUtils.isEmpty(ids)) {return Collections.emptyList();}List<Goods> goods = new ArrayList<>(ids.size() * 2);// 循环idsids.forEach(id -> {// 从数据库拿到数据Goods g = db.get(id);if (!ObjectUtils.isEmpty(g)) {goods.add(g);}});return goods;}
}

6.5.3 创建倒排索引的数据结构

public class InvertedIndex {/*** 倒排索引 key = 分词,value= ids*/public static Map<String, Set<Integer>> index = new HashMap<>();}

6.5.4 创建GoodsService接口

public interface GoodsService {/*** 添加商品的方法** @param goods*/void addGoods(Goods goods);/*** 根据商品名称查询** @param name* @return*/List<Goods> findGoodsByName(String name);/*** 根据关键字查询** @param keywords* @return*/List<Goods> findGoodsByKeywords(String keywords);}

6.5.5 创建GoodsServiceImpl实现类

@Service
public class GoodsServiceImpl implements GoodsService {@Autowiredprivate JiebaSegmenter jiebaSegmenter;/*** 添加商品的方法* 1.先对商品名称进行分词,拿到了List<String> tokens* 2.将商品插入数据库 拿到商品id* 3.将tokens和id放入倒排索引中index** @param goods*/@Overridepublic void addGoods(Goods goods) {// 分词List<String> keywords = fenci(goods.getGoodsName());// 插入数据库DBUtil.insert(goods);// 保存到倒排索引中saveToInvertedIndex(keywords, goods.getGoodsId());}/*** 保存到倒排索引的方法** @param keywords* @param goodsId*/private void saveToInvertedIndex(List<String> keywords, Integer goodsId) {// 拿到索引Map<String, Set<Integer>> index = InvertedIndex.index;// 循环分词集合keywords.forEach(keyword -> {Set<Integer> ids = index.get(keyword);if (CollectionUtils.isEmpty(ids)) {// 如果之前没有这个词 就添加进去HashSet<Integer> newIds = new HashSet<>(2);newIds.add(goodsId);index.put(keyword, newIds);} else {// 说明之前有这个分词 我们记录idids.add(goodsId);}});}/*** 分词的方法** @param goodsName* @return*/private List<String> fenci(String goodsName) {List<SegToken> tokens = jiebaSegmenter.process(goodsName, JiebaSegmenter.SegMode.SEARCH);return tokens.stream().map(token -> token.word).collect(Collectors.toList());}/*** 根据商品名称查询** @param name* @return*/@Overridepublic List<Goods> findGoodsByName(String name) {// 查询倒排索引中 是否有这个词Map<String, Set<Integer>> index = InvertedIndex.index;Set<Integer> ids = index.get(name);if (CollectionUtils.isEmpty(ids)) {// 查询数据库 模糊匹配去} else {// 说明分词有 根据ids 查询数据库return DBUtil.getGoodsByIds(ids);}return Collections.emptyList();}/*** 根据关键字查询** @param keywords* @return*/@Overridepublic List<Goods> findGoodsByKeywords(String keywords) {// 进来先把关键字分词一下List<String> tokens = fenci(keywords);// 拿到倒排索引Map<String, Set<Integer>> index = InvertedIndex.index;Set<Integer> realIds = new HashSet<>();// 循环分词集合 查询倒排索引tokens.forEach(token -> {Set<Integer> ids = index.get(token);if (!CollectionUtils.isEmpty(ids)) {// 如果局部的ids不为空,就添加到总的ids里面去realIds.addAll(ids);}});// 查询数据库return DBUtil.getGoodsByIds(realIds);}
}

6.5.6 编写测试类

@Autowired
public GoodsService goodsService;/*** 测试我们自己写的倒排索引** @throws Exception*/
@Test
public void testMyIndex() throws Exception {// 造数据Goods goods = new Goods(1, "苹果手机", 10.00);Goods goods1 = new Goods(2, "华为手机", 11.00);Goods goods2 = new Goods(3, "红米手机", 5.00);Goods goods3 = new Goods(4, "联想手机", 6.00);goodsService.addGoods(goods);goodsService.addGoods(goods1);goodsService.addGoods(goods2);goodsService.addGoods(goods3);// 查询goodsService.findGoodsByName("苹果手机").forEach(System.out::println);System.out.println("--------------------------------------------");goodsService.findGoodsByKeywords("苹果手机").forEach(System.out::println);
}

7.Elasticsearch安装

下载地址 https://www.elastic.co/cn/downloads/past-releases#elasticsearch

echo 3 > /proc/sys/vm/drop_caches
在这里插入图片描述

1.Docker拉取镜像,我们选7.15.2版本,因为springboot的2.6.3版指定的是这个版本

docker pull elasticsearch:7.15.2

  1. 运行镜像

docker run -d --name elasticsearch --net=host -p 9200:9200 -p 9300:9300 -e “discovery.type=single-node” -e ES_JAVA_OPTS=“-Xms256m -Xmx256m” elasticsearch:7.15.2

  1. 试访问 ip:9200

在这里插入图片描述

  1. 意外

错误:max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144],你最少需要262144的内存

运行:sysctl -w vm.max_map_count=262144

重启容器就ok 了

8.Elasticsearch目录学习

在这里插入图片描述在这里插入图片描述

bin:启动脚本

config:

elasticsearch.yml,ES的集群信息、对外端口、内存锁定、数据目录、跨域访问等属性的配置

jvm.options,ES使用Java写的,此文件用于设置JVM相关参数,如最大堆、最小堆

log4j2.properties,ES使用log4j作为其日志框架

data:数据存放目录(索引数据)

plugins: ES的可扩展插件存放目录,如可以将ik中文分词插件放入此目录,ES启动时会自动加载

9.Elasticsearch可视化插件的安装

9.1 谷歌插件方式
在这里插入图片描述
在这里插入图片描述

9.2 Docker镜像方式安装(和9.1选择一个玩)
在这里插入图片描述

docker run --name eshead -p 9100:9100 -d mobz/elasticsearch-head:5

9.3 解决跨域问题
在这里插入图片描述

1.进入elasticsearch容器

docker exec -it elasticsearch bash

2.进入配置文件

cd /usr/share/elasticsearch/config

  1. 修改elasticsearch.yml配置文件,

vi elasticsearch.yml

  1. 结尾添加

http.cors.enabled: true

http.cors.allow-origin: “*”

  1. 重启elasticsearch后访问即可

docker restart elasticsearch

10.IK分词的安装【重点】**

Ik分词在es 里面也是插件的形式安装的

10.1 没有ik分词的时候
在这里插入图片描述

10.2 IK分词安装(方式一受网速影响)

  1. 找对应的ES版本的IK分词

https://github.com/medcl/elasticsearch-analysis-ik/releases

  1. 进入容器 docker exec -it elasticsearch bash

  2. 进入这个目录 /usr/share/elasticsearch/bin

  3. 执行命令 install 后面的连接就是从上面找到的对应的版本下载链接

./elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.15.2/elasticsearch-analysis-ik-7.15.2.zip

  1. 下载完成
    在这里插入图片描述

10.3 IK分词安装(方式二推荐)

  1. 找对应的ES版本的IK分词 https://github.com/medcl/elasticsearch-analysis-ik/releases

  2. 下载到windows上

  3. 将zip文件拷贝到linux上

  4. docker cp linux的路径 elasticsearch:/usr/share/elasticsearch/plugins
    在这里插入图片描述

  5. 进容器后解压,注意名字unzip elasticsearch-analysis-ik-7.15.2.zip -d ./ik/

  6. 删掉zip文件 elasticsearch-analysis-ik-7.15.2.zip

10.4 重启ES测试
docker restart elasticsearch

Ik分词的两种方式:

ik_smart:分词的粒度较小,也叫智能分词
在这里插入图片描述

ik_max_word:分词的粒度较大,也叫最大力度分词
在这里插入图片描述

10.5 自定义分词【了解】
进入容器
在这里插入图片描述

11.Elasticsearch核心概念【重点】

一个json串 叫文档 es又被叫文档性数据库

11.1 结构说明
在这里插入图片描述

11.2 索引库(indices)
把数据写入elasticsearch 时,会在里面建立索引,索引库里面存储索引,一个index 对应一个database

11.3 文档(document)
就是一条数据,一般使用json 表示,和数据库对比,就是一行数据,在java 里面就是一个一个对象

11.4 字段(field)
一个对象的属性,对应数据库就是一列

11.5 节点
一台运行elasticsearch的服务器,被称为一个节点

11.6 集群
多个节点组成一个集群

11.7 分片
一个索引可以存储在多个主分片上,有负载均衡的作用,还有从分片是主分片的一个副本

11.8 副本
一份数据可以有多个副本,做数据冗余(安全),一般放在从分片里面
在这里插入图片描述

12.Elasticsearch基本使用(重点)

Elasticsearch 是基于restful风格的http应用

Restful风格就是使用http动词形式对url资源进行操作(GET,POST,PUT,DELETE…)

操作格式为:

请求类型 ip:port/索引名/_doc/文档id

{请求体}

12.1 对索引和mappings的操作(建库建表约束)
12.1.1 新增索引
PUT http://192.168.226.128:9200/student 新建一个student索引,给定几个字段约束

索引只能增删,不能修改

{"mappings": {"properties": {"name":{"type": "text"},"age":{"type": "integer"},"birthDay":{"type": "date"},"price":{"type": "double"}}}}

查询索引信息
在这里插入图片描述

查询索引的mappings信息
在这里插入图片描述

12.1.2 删除索引
DELETE http://192.168.226.128:9200/student

12.2 对Document的操作
12.2.1 新增数据(方便后面演示,自己多新增几条)
使用put请求新增时需要自己指定id,使用post请求新增时系统会自动生成一个id

PUT http://192.168.226.128:9200/user/_doc/1 请求解释

user: 索引名称

_doc:类型(即将剔除,官方建议全部使用_doc)

1: 文档id
在这里插入图片描述

从head插件里面查看数据
在这里插入图片描述

12.2.2 修改一个数据

  1. 危险的修改,把其他的字段值都删了

PUT http://192.168.226.128:9200/user/_doc/2
在这里插入图片描述在这里插入图片描述

  1. 安全的修改,其他的字段值会保留

POST http://192.168.226.128:9200/user/_doc/2/_update
在这里插入图片描述在这里插入图片描述

12.2.3 删除一个数据
DELETE http://192.168.226.128:9200/user/_doc/3
在这里插入图片描述在这里插入图片描述

12.2.4 查询一个数据
GET http://192.168.226.128:9200/user/_doc/1
在这里插入图片描述

12.2.5 查询全部数据
GET http://192.168.226.128:9200/user/_doc/_search

13.SpringBoot使用ES【重点】

13.1 新建项目选择依赖
在这里插入图片描述

13.2 修改配置文件
spring:
elasticsearch:
uris: http://192.168.226.129:9200

13.3 测试连接ES
说明我们连接成功,下面开始操作
在这里插入图片描述

13.4 对索引的操作,我们直接使用实体类操作
13.4.1 新建Goods实体类

/*** @Document是ES提供的注解 indexName:索引名称* createIndex:启动时是否创建* shards:分片个数* replicas:副本个数* refreshInterval:数据导入到索引里面,最多几秒搜索到*/@Data
@AllArgsConstructor
@NoArgsConstructor
@Setting(shards = 2,replicas = 1,refreshInterval = "1s")
@Document(indexName = "goods_index")
public class Goods {/*** 商品ID*/@Id //默认使用keyword关键字模式,不进行分词@Fieldprivate Integer goodsId;/*** 商品名称* analyzer:导入时使用的分词* searchAnalyzer:搜索时使用的分词*/@Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")private String goodsName;/*** 商品描述*/@Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")private String goodsDesc;/*** 商品价格*/@Field(type = FieldType.Double)private Double goodsPrice;/*** 商品的销量*/@Field(type = FieldType.Long)private Long goodsSaleNum;/*** 商品的卖点*/@Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")private String goodsBrief;/*** 商品的状态*/@Field(type = FieldType.Integer)private Integer goodsStatus;/*** 商品的库存*/@Field(type = FieldType.Integer)private Integer goodsStock;/*** 商品的标签*/@Field(type = FieldType.Text)private List<String> goodsTags;/*** 上架的时间* 指定时间格式化*/private Date goodsUpTime;}

13.5 对文档的操作,我们熟悉的CRUD
13.5.1 创建goodsDao

@Repository
public interface GoodsDao extends ElasticsearchRepository<Goods, Integer> {}

13.5.2 新增数据

@Autowired
private GoodsDao goodsDao;/*** 描述: 对document的curd** @param :* @return void*/
@Test
public void testDocumentCurd() throws Exception {//新增商品数据100条ArrayList<Goods> goods = new ArrayList<>(200);for (int i = 1; i <= 100; i++) {goods.add(new Goods(i,i % 2 == 0 ? "华为电脑" + i : "联想电脑" + i,i % 2 == 0 ? "轻薄笔记本" + i : "游戏笔记本" + i,4999.9 + i,999L,i % 2 == 0 ? "华为续航强" : "联想性能强",i % 2 == 0 ? 1 : 0,666 + i,i % 2 == 0 ? Arrays.asList("小巧", "轻薄", "续航") : Arrays.asList("炫酷", "畅玩", "游戏"),new Date()));}goodsDao.saveAll(goods);
}

13.5.3 修改数据(注意是危险修改)

@Test
public void testUpdate() throws Exception {goodsDao.save(new Goods(1, "小米笔记本", null, null, null, null, null, null, null, null));
}

13.5.4 删除数据

@Test
public void testDelete() throws  Exception{goodsDao.deleteById(1);
}

13.5.5 根据id查询数据

@Test
public void testSearchById() throws Exception {Optional<Goods> byId = goodsDao.findById(502);System.out.println(byId.get());
}

13.5.6 查询所有数据

@Test
public void testSearchAll() throws Exception {Iterable<Goods> all = goodsDao.findAll();all.forEach(System.out::println);
}

14.复杂的查询操作【重点】

14.1 查询注意点
match:会通过分词器去模糊匹配 例如:华为电脑,会把包含‘华为’,‘电脑’,都查出来

matchPhrase:不分词查询,弥补了match和term

term:精确查找你的关键字,一般使用keywords的约束,使用term

rang:范围查询

match 和 rang 如果同时出现,需要组合bool查询

分页,排序是通用的查询,不需要通过bool组合使用,直接nativeSearchQueryBuilder使用

14.2 查询常用类
QueryBuilders:构造条件对象,例如matchQuery,rangeQuery,boolQuery等

NativeSearchQueryBuilder:组合条件对象,组合后使用build构建查询对象

HighlightBuilder:高亮的查询类,注意使用它的Field静态内部类

FunctionScoreQueryBuilder:权重类,注意它的FilterFunctionBuilder静态内部类

14.3 关键字,范围,分页,排序

@Test
public void testFuZaSearch() throws Exception {//关键字,“华为” ,范围,分页,排序MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("goodsName", "华为");RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("goodsStock").from(700).to(750);//使用bool组合这两个查询BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery().must(matchQueryBuilder).must(rangeQueryBuilder);//创建组合器NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();//去build()构建查询对象NativeSearchQuery nativeSearchQuery = nativeSearchQueryBuilder.withQuery(boolQueryBuilder).withPageable(PageRequest.of(0, 20))    //注意范围和分页有关系,可能查出来了,但是当前分页没有.withSort(SortBuilders.fieldSort("goodsPrice").order(SortOrder.ASC)).build();//使用es查询 得到结果集SearchHits<Goods> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, Goods.class);searchHits.forEach(goodsSearchHit -> {//循环结果集,答应结果System.out.println(goodsSearchHit.getContent());});
}

14.4 高亮查询

@Testpublic void testHighlight() throws Exception {//华为,模糊匹配MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("goodsName", "华为");HighlightBuilder.Field goodsName = new HighlightBuilder.Field("goodsName").preTags("<span style='color:red'>").postTags("</span>");NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();NativeSearchQuery nativeSearchQuery = nativeSearchQueryBuilder.withQuery(matchQueryBuilder).withHighlightFields(goodsName).build();//得到结果集 我们需要手动组装高亮字段SearchHits<Goods> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, Goods.class);List<Goods> goodsArrayList = new ArrayList<>();searchHits.forEach(goodsSearchHit -> {//得到goods对象,但是这里面额goodsName属性不是高亮的,所以要改Goods goods = goodsSearchHit.getContent();List<String> highlightField = goodsSearchHit.getHighlightField("goodsName");String highlight = highlightField.get(0);goods.setGoodsName(highlight);goodsArrayList.add(goods);});System.out.println(JSON.toJSONString(goodsArrayList));}
}

14.5 权重查询

@Test
public void testWeight() throws Exception {//手机名称 和卖点 都有的情况下,设置权重查询String keyWords = "华为";//创建权重数组FunctionScoreQueryBuilder.FilterFunctionBuilder[] functionBuilders = new FunctionScoreQueryBuilder.FilterFunctionBuilder[2];//设置权重functionBuilders[0] = (new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery("goodsName", keyWords),ScoreFunctionBuilders.weightFactorFunction(10)//给名称设置10的权重大小));functionBuilders[1] = (new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery("goodsBrief", keyWords),ScoreFunctionBuilders.weightFactorFunction(4)//给卖点设置4的权重));FunctionScoreQueryBuilder functionScoreQueryBuilder = new FunctionScoreQueryBuilder(functionBuilders);functionScoreQueryBuilder.setMinScore(2) //设置最小分数.scoreMode(FunctionScoreQuery.ScoreMode.FIRST);//设置计分方式NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().withQuery(functionScoreQueryBuilder).build();SearchHits<Goods> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, Goods.class);searchHits.forEach(goodsSearchHit -> {//循环结果集,答应结果System.out.println(goodsSearchHit.getContent());});
}

15.ES集群(了解)

这里使用windows方式演示集群

Linux上的集群道理一样,修改配置文件即可

可以参考https://my.oschina.net/u/4353003/blog/4333773

15.1 创建三个es节点
解压出三个来
在这里插入图片描述

15.2 修改配置文件
15.2.1 Node1修改配置文件
进入elasticsearch-7.15.2-node1\config下,修改elasticsearch.yml

# 设置集群名称,集群内所有节点的名称必须一致。cluster.name: my-esCluster# 设置节点名称,集群内节点名称必须唯一。node.name: node1# 表示该节点会不会作为主节点,true表示会;false表示不会node.master: true# 当前节点是否用于存储数据,是:true、否:falsenode.data: true# 索引数据存放的位置#path.data: /opt/elasticsearch/data# 日志文件存放的位置#path.logs: /opt/elasticsearch/logs# 需求锁住物理内存,是:true、否:false#bootstrap.memory_lock: true# 监听地址,用于访问该esnetwork.host: 0.0.0.0# es对外提供的http端口,默认 9200http.port: 9200# TCP的默认监听端口,默认 9300transport.tcp.port: 9300# 设置这个参数来保证集群中的节点可以知道其它N个有master资格的节点。默认为1,对于大的集群来说,可以设置大一点的值(2-4)discovery.zen.minimum_master_nodes: 2# es7.x 之后新增的配置,写入候选主节点的设备地址,在开启服务后可以被选为主节点discovery.seed_hosts: ["192.168.186.1:9300", "192.168.186.1:9301", "192.168.186.1:9302"]discovery.zen.fd.ping_timeout: 1mdiscovery.zen.fd.ping_retries: 5# es7.x 之后新增的配置,初始化一个新的集群时需要此配置来选举mastercluster.initial_master_nodes: ["node1", "node2", "node3"]# 是否支持跨域,是:true,在使用head插件时需要此配置http.cors.enabled: true# “*” 表示支持所有域名http.cors.allow-origin: "*"action.destructive_requires_name: trueaction.auto_create_index: .security,.monitoring*,.watches,.triggered_watches,.watcher-history*xpack.security.enabled: falsexpack.monitoring.enabled: truexpack.graph.enabled: falsexpack.watcher.enabled: falsexpack.ml.enabled: false

15.2.2 Node2修改配置文件

# 设置集群名称,集群内所有节点的名称必须一致。cluster.name: my-esCluster# 设置节点名称,集群内节点名称必须唯一。node.name: node2# 表示该节点会不会作为主节点,true表示会;false表示不会node.master: true# 当前节点是否用于存储数据,是:true、否:falsenode.data: true# 索引数据存放的位置#path.data: /opt/elasticsearch/data# 日志文件存放的位置#path.logs: /opt/elasticsearch/logs# 需求锁住物理内存,是:true、否:false#bootstrap.memory_lock: true# 监听地址,用于访问该esnetwork.host: 0.0.0.0# es对外提供的http端口,默认 9200http.port: 9201# TCP的默认监听端口,默认 9300transport.tcp.port: 9301# 设置这个参数来保证集群中的节点可以知道其它N个有master资格的节点。默认为1,对于大的集群来说,可以设置大一点的值(2-4)discovery.zen.minimum_master_nodes: 2# es7.x 之后新增的配置,写入候选主节点的设备地址,在开启服务后可以被选为主节点discovery.seed_hosts: ["192.168.186.1:9300", "192.168.186.1:9301", "192.168.186.1:9302"]discovery.zen.fd.ping_timeout: 1mdiscovery.zen.fd.ping_retries: 5# es7.x 之后新增的配置,初始化一个新的集群时需要此配置来选举mastercluster.initial_master_nodes: ["node1", "node2", "node3"]# 是否支持跨域,是:true,在使用head插件时需要此配置http.cors.enabled: true# “*” 表示支持所有域名http.cors.allow-origin: "*"action.destructive_requires_name: trueaction.auto_create_index: .security,.monitoring*,.watches,.triggered_watches,.watcher-history*xpack.security.enabled: falsexpack.monitoring.enabled: truexpack.graph.enabled: falsexpack.watcher.enabled: falsexpack.ml.enabled: false

15.2.3 Node3修改配置文件

# 设置集群名称,集群内所有节点的名称必须一致。cluster.name: my-esCluster# 设置节点名称,集群内节点名称必须唯一。node.name: node3# 表示该节点会不会作为主节点,true表示会;false表示不会node.master: true# 当前节点是否用于存储数据,是:true、否:falsenode.data: true# 索引数据存放的位置#path.data: /opt/elasticsearch/data# 日志文件存放的位置#path.logs: /opt/elasticsearch/logs# 需求锁住物理内存,是:true、否:false#bootstrap.memory_lock: true# 监听地址,用于访问该esnetwork.host: 0.0.0.0# es对外提供的http端口,默认 9200http.port: 9202# TCP的默认监听端口,默认 9300transport.tcp.port: 9302# 设置这个参数来保证集群中的节点可以知道其它N个有master资格的节点。默认为1,对于大的集群来说,可以设置大一点的值(2-4)discovery.zen.minimum_master_nodes: 2# es7.x 之后新增的配置,写入候选主节点的设备地址,在开启服务后可以被选为主节点discovery.seed_hosts: ["192.168.186.1:9300", "192.168.186.1:9301", "192.168.186.1:9302"]discovery.zen.fd.ping_timeout: 1mdiscovery.zen.fd.ping_retries: 5# es7.x 之后新增的配置,初始化一个新的集群时需要此配置来选举mastercluster.initial_master_nodes: ["node1", "node2", "node3"]# 是否支持跨域,是:true,在使用head插件时需要此配置http.cors.enabled: true# “*” 表示支持所有域名http.cors.allow-origin: "*"action.destructive_requires_name: trueaction.auto_create_index: .security,.monitoring*,.watches,.triggered_watches,.watcher-history*xpack.security.enabled: falsexpack.monitoring.enabled: truexpack.graph.enabled: falsexpack.watcher.enabled: falsexpack.ml.enabled: false

15.3 启动es

进入bin目录下 逐个启动,三台全部双击启动,注意不要关闭黑窗口

15.4 访问查看集群信息和状态
访问查看:http://127.0.0.1:9200/_cat/nodes
在这里插入图片描述

也可以使用head插件查看
在这里插入图片描述

15.5 SpringBoot连接es集群
spring:
elasticsearch:
uris:
- http://127.0.0.1:9200
- http://127.0.0.1:9201
- http://127.0.0.1:9202

16.Es总结面试

16.1 为什么使用es (结合项目业务来说)
商城中的数据,将来会非常多,所以采用以往的模糊查询,模糊查询前置配置,会放弃索引,(%name%)导致商品查询是全表扫描,在百万级别的数据库中,效率非常低下,而我们使用ES做一个全文索引,我们将经常查询的商品的某些字段,比如说商品名,描述、价格还有id这些字段我们放入我们索引库里,可以提高查询速度。 (数据量过大,而且用户经常使用查询的场景,对用户体验很好)

16.2 es用来做什么(场景)重点

  1. 商品存放 (业务数据的存放) 每个商品都是一个对象

  2. 日志统计 (整个应用的日志非常多,都要收集起来,方便后期做日志分析,数据回溯)

  3. 数据分析(大数据)(只要是电商,就要和tb,jd等对比价格,做数据分析等)

你做一个电商项目 你卖鞋子 衣服 你怎么 定价 鞋子 199 599 398

你写个爬虫 定期采集tb jd的数据库 做数据比对分析 做 竞品 分析

定期的做数据采集和分析 数据采集系统 定时任务去采集别的大型电商网站的数据,进行价格分析,从而定价,后期还要做竞品分析

16.3 什么是倒排索引
通常正排索引是通过id映射到对应的数据

倒排索引是将分词建立索引,通过分词映射到id,在通过id找到数据

详见文档4.2

16.4 es的存储数据的过程
在这里插入图片描述

1:写入请求,分发节点。

2:数据写入同时写入内存和translog各一份,tanslog为保证数据不丢失,每 5 秒,或每次请求操作结束前,会强制刷新 translog 日志到磁盘上

3:确定数据给那个分片,refresh 刷新内存中数据到分片的segment,默认1秒刷新一次,为了提高吞吐量可以增大60s。参数refresh_interval(refresh操作使得写入文档搜索可见)

4:通过flush操作将segment刷新到磁盘中完成持久化,保存成功清除translog,新版本es的 translog 不会在 segment 落盘就删,而是会保留,默认是512MB,保留12小时。每个分片。所以分片多的话 ,要考虑 translog 会带来的额外存储开销(flush操作使得filesystem cache写入磁盘,以达到持久化的目的) (refresh之前搜索不可见)

5:segment过多会进行合并merge为大的segment,消耗大量的磁盘io和网络io (方便数据整理和磁盘优化)

16.5 es的搜索过程
1、搜索被执行成一个两阶段过程,我们称之为 Query Then Fetch;

2、在初始查询阶段时,查询会广播到索引中每一个分片拷贝(主分片或者副本分

片)。 每个分片在本地执行搜索并构建一个匹配文档的大小为 from + size 的

优先队列。

注意:在搜索的时候是会查询 Filesystem Cache 的,但是有部分数据还在 Memory

Buffer,所以搜索是接近实时的。

3、每个分片返回各自优先队列中所有文档的 ID 和排序值给协调节点(主节点),它合并

这些值到自己的优先队列中来产生一个全局排序后的结果列表。

4、接下来就是 取回阶段,协调节点辨别出哪些文档需要被取回并向相关的分片

提交多个 GET 请求。每个分片加载并 丰富 文档,如果有需要的话,接着返回

文档给协调节点。一旦所有的文档都被取回了,协调节点返回结果给客户端。

通俗的将就是:

每个分片先拿到id和排序值,然后整合成一个全局列表

然后通过判断找到相应的节点提交多个get请求,组装数据返回

https://javajl.yuque.com/docs/share/61000afe-fc17-4bb7-9279-63bfba5fd6cc?# 《Elasticsearch 7.x(入门)》密码:yk91

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/206670.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Ambari】Python调用Rest API 获取YARN HA状态信息并发送钉钉告警

&#x1f984; 个人主页——&#x1f390;开着拖拉机回家_Linux,大数据运维-CSDN博客 &#x1f390;✨&#x1f341; &#x1fa81;&#x1f341;&#x1fa81;&#x1f341;&#x1fa81;&#x1f341;&#x1fa81;&#x1f341; &#x1fa81;&#x1f341;&#x1fa81;&am…

二层交换原理

二层交换设备工作在OSI模型的第二层&#xff0c;即数据链路层&#xff0c;它对数据包的转发是建立在MAC&#xff08;Media Access Control &#xff09;地址基础之上的。二层交换设备不同的接口发送和接收数据独立&#xff0c;各接口属于不同的冲突域&#xff0c;因此有效地隔离…

【C/PTA —— 15.结构体2(课内实践)】

C/PTA —— 15.结构体2&#xff08;课内实践&#xff09; 7-1 计算职工工资7-2 计算平均成绩7-3 找出总分最高的学生7-4 通讯录的录入与显示 7-1 计算职工工资 #include<stdio.h> #include<stdlib.h> typedef struct GZ {char name[6];double j;double f;double z;…

记一次由 jedis 引发的离谱选学问题

背景 我的应用中&#xff0c;使用 jedis 作为连接 redis 的客户端&#xff0c;一直在用的好好的&#xff0c;后来有一个新的组件&#xff0c;也需要使用 redis&#xff0c;但是组件是内部封装的&#xff0c;我只能提供一个 StringReidsTempalte&#xff0c;所以我基于应用本身…

【无线网络技术】——无线广域网(学习笔记)

&#x1f4d6; 前言&#xff1a;无线广域网(WWAN)是指覆盖全国或全球范围内的无线网络&#xff0c;提供更大范围内的无线接入&#xff0c;与无线个域网、无线局域网和无线城域网相比&#xff0c;它更加强调的是快速移动性。典型的无线广域网&#xff1a;蜂窝移动通信系统和卫星…

Java期末复习题之抽象类、接口

点击返回标题->23年Java期末复习-CSDN博客 第1题. 首先设计一个学生抽象类Student&#xff0c;其数据成员有name(姓名)、age(年龄)和degree(学位)&#xff0c;以及一个抽象方法show()。然后由Student类派生出本科生类Undergraduate和研究生类Graduate&#xff0c;本科生类Un…

第 7 部分 — 增强 LLM 安全性的策略:数学和伦理框架

一、说明 增强大型语言模型 (LLM) 安全性的追求是技术创新、道德考虑和实际应用的复杂相互作用。这项努力需要一种深入而富有洞察力的方法&#xff0c;将先进的数学模型与道德原则和谐地融合在一起&#xff0c;以确保LLM的发展不仅在技术上稳健&#xff0c;而且在道德上合理且对…

网络攻击(一)--安全渗透简介

1. 安全渗透概述 目标 了解渗透测试的基本概念了解渗透测试从业人员的注意事项 1.1. 写在前面的话 在了解渗透测试之前&#xff0c;我们先看看&#xff0c;信息安全相关的法律是怎么样的 中华人民共和国网络安全法 《中华人民共和国网络安全法》由全国人民代表大会常务委员会…

Spring Cloud切换内嵌Tomcat为宝兰德Application Server

目录 替换Tomcat中间件Tomcat是什么Spring Cloud剔除tomcat引入宝兰德Application Server打包运行授权导入 替换Tomcat中间件 Tomcat是什么 Spring Cloud剔除tomcat <!--集成springmvc框架 --><dependency><groupId>org.springframework.boot</groupId&…

Java安全之Commons Collections6分析

CC6分析 import org.apache.commons.collections.*; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.functors.InvokerTransformer; impo…

上网监控软件——安全与隐私的平衡

网络已经成为人们生活和工作中不可或缺的一部分。然而&#xff0c;随着网络使用的普及&#xff0c;网络安全问题也日益突出。上网监控软件作为网络安全领域的一个重要组成部分&#xff0c;在保护企业和家庭网络安全方面发挥着重要作用。 本文将探讨上网监控软件的背景、功能、优…

1-2算法基础-常用库函数

1.排序 sort(first,last,cmp) first指向要排序范围的第一个元素&#xff0c;从0起 last指向要排序范围的最后一个元素的下一个位置 cmp&#xff08;可选&#xff09;&#xff0c;自定义函数&#xff0c;默认从小到大 评测系统 #include <iostream> #include<algorith…

Java一对一聊天

服务端 package 一对一用户;import java.awt.BorderLayout; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Vector;…

three.js 入门三:buffergeometry贴图属性(position、index和uvs)

环境&#xff1a; three.js 0.159.0 一、基础知识 geometry&#xff1a;决定物体的几何形状、轮廓&#xff1b;material&#xff1a;决定物体呈现的色彩、光影特性、贴图皮肤&#xff1b;mesh&#xff1a;场景中的物体&#xff0c;由geometry和materia组成&#xff1b;textu…

十五、机器学习进阶知识:K-Means聚类算法

文章目录 1、聚类概述2、K-Means聚类算法原理3、K-Means聚类实现3.1 基于SKlearn实现K-Means聚类3.2 自编写方式实现K-Means聚类 4、算法不足与解决思路4.1 存在的问题4.2 常见K值确定方法4.3 算法评估优化思路 1、聚类概述 聚类&#xff08;Clustering&#xff09;是指将不同…

浅谈WPF之控件拖拽与拖动

使用过office的visio软件画图的小伙伴都知道&#xff0c;画图软件分为两部分&#xff0c;左侧图形库&#xff0c;存放各种图标&#xff0c;右侧是一个画布&#xff0c;将左侧图形库的图标控件拖拽到右侧画布&#xff0c;就会生成一个新的控件&#xff0c;并且可以自由拖动。那如…

1 接口测试介绍

在软件测试工作中&#xff0c;接口测试是必不可少的。接口测试一般是发生在单元测试之后&#xff0c;系统测试之前。当开发人员输出API文档后&#xff0c;测试人员就可以开始编写接口测试用例了。接口测试可以让测试人员更早的介入&#xff0c;不需要等待前后端联调完成才开始测…

银行卡二要素API的应用案例:从在线购物到金融投资

引言 随着互联网技术的不断发展&#xff0c;人们的金融需求也在不断增加。随之而来的是各种新型金融服务的涌现&#xff0c;让用户的金融体验更加便利快捷。其中&#xff0c;银行卡二要素API的应用&#xff0c;则为用户的金融体验和安全性提供了极大的保障。 银行卡二要素API…

知识蒸馏的蒸馏损失方法代码总结(包括:基于logits的方法:KLDiv,dist,dkd等,基于中间层提示的方法:)

有两种知识蒸馏方法&#xff1a;一种利用教师模型的输出概率&#xff08;基于logits的方法&#xff09;[15,14,11]&#xff0c;另一种利用教师模型的中间表示&#xff08;基于提示的方法&#xff09;[12,13,18,17]。基于logits的方法利用教师的输出作为辅助信号来训练一个较小的…

【STM32】TIM定时器输出比较

1 输出比较 1.1 输出比较简介 OC&#xff08;Output Compare&#xff09;输出比较&#xff1b;IC&#xff08;Input Capture&#xff09;输入捕获&#xff1b;CC&#xff08;Capture/Compare&#xff09;输入捕获和输出比较的单元输出比较可以通过比较CNT与CCR寄存器值&#…