Elasticsearch的思想
- 将需要存入的数据,除去存入数据库外,另存入Elasticsearch服务器中一份,并对数据中的属性进行分词
- Elasticsearch服务器中存储进行分词后的各种数据,使用键值对进行保存。键为分割的词,值为存储的数据
- 当需要查询数据时候,查询Elasticsearch服务器,服务器会将输入的查询数据进行分词,并对自己内部保存的键值对的键进行匹配,将键值匹配的所有的值返回,就可以得到模糊匹配的搜索结果
ps:小弟总结的,不对的话大佬们请指出
Elasticsearch的核心概念
索引库(Indices):索引库里面存储索引,一个索引库对应一个DataBase(数据库)。
类型(Type):索引库里面存储索引,一个索引库对应一个DataBase(数据库),那么索引库里面的一个索引就对应数据库里面的一张表,而Type其实就是索引名(表名)一样。
文档(Document):就是索引里面的一条数据,一般都是Json数据。和数据库对比,就是表中的一行数据,在java 里面就对应一个对象。
字段(Field):Json中的属性,对象的属性,对应数据库表中的列。
Mappings:字段的映射,相当于表中列的类型约束(int,varchar…)
Elasticsearch Mysql Indices(索引库) DataBase(数据库) Type_doc–Index(索引) Table(表) Document(文档)–JSON Row(行) Field(字段) Column(列) Mappings(映射) 列的类型约束(int,varchar…) 节点:一台运行elasticsearch的服务器,被称为一个节点。
集群:多个节点组成一个集群。
分片:一个索引可以存储在多个主分片上,有负载均衡的作用,还有从分片是主分片的一个副本。
副本:一份数据可以有多个副本,做数据冗余(安全),一般放在从分片里面。
Elasticsearch基本使用
Elasticsearch是基于Restful风格的http应用。
Restful风格就是使用http动词形式对url资源进行操作(GET(查)、POST(改)、PUT(增)、DELETE(删))。
Springboot创建索引
pom文件
<!-- 引入elasticsearch的启动器依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency>
配置文件:application.properties
#连接ES spring.elasticsearch.rest.uris=http://192.168.9.128:9200
创建索引
@Data @AllArgsConstructor @NoArgsConstructor @ToString /* * @Document() 注解的 主要属性 * indexName:设置索引名称;格式一般为类名_index * refreshInterval:设置索引的刷新间隔 * shards:设置创建几个主片 * replicas:设置每个主片有几个从片 */ @Document(indexName = "good_index") public class Goods { /* @Field() 注解的 主要属性: 1)name/value属性:指定实体类的属性映射的索引的字段名,如果不指定默认就是实体类的属性名; 2)type:指定索引的数据类型,值是FieldType的枚举值 一般给id字段的类型是FieldType.Keyword,表示关键字,且不会分词 属性的数据类型为String时候,对应的FieldType的枚举值为FieldType.Text 属性的数据类型为Date时候,对应的FieldType的枚举值为FieldType.Date,并且指明格式化方式 3)format = DateFormat.date;当参数的数据类型为Date时候,改参数为设置Date的格式化方式 4)analyzer = "ik_max_word":表示给字段添加数据时使用ik_max_word模式进行分词{添加属性后对改属性的值进行分词}; 5)searchAnalyzer = "ik_max_word":表示搜索字段也使用ik_max_word模式进行分词{添加属性后对改属性的值进行分词}; @Id 注解:表示goodsId属性是索引的文档id(主键id); */ @Id @Field(value = "goodsId", type = FieldType.Keyword) private Integer goodsId; @Field(value = "goodsName", type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_max_word") private String goodsName; /* 价格因为不用进行分词,所以就不需要添加analyzer属性和searchAnalyzer属性了 */ @Field(value = "goodsPrice") private Double goodsPrice; @Field(value = "goodsUpTime", type = FieldType.Date, format = DateFormat.date) private Date goodsUpTime; }
创建接口,继承ElasticsearchRepository接口;标记@Repository注解
/* 继承的接口ElasticsearchRepository的泛型: 1)索引映射的实体类类型 2)索引的主键id的类型 */ @Repository public interface CreateGoodsIndex extends ElasticsearchRepository<Goods, Integer> { }
在启动项目的时候,就会根据实体类中声明的属性,创建索引
Springboot针对索引的基本的CRUD
添加信息:
//注入继承接口ElasticsearchRepository的那个自定义的接口 @Autowired private CreateGoodsIndex generateGoodsIndex;
generateGoodsIndex.save(new Goods(1, "张三峰", 1000D, new Date())); //添加单行数据
//一次添加多行数据 ArrayList<Goods> goods = new ArrayList<>(); goods.add(new Goods(2, "张四峰", 1000D, new Date())); goods.add(new Goods(3, "张五峰", 1000D, new Date())); goods.add(new Goods(4, "张六峰", 1000D, new Date())); goods.add(new Goods(5, "张七峰", 1000D, new Date())); goods.add(new Goods(6, "张八峰", 1000D, new Date())); generateGoodsIndex.saveAll(goods);
删除信息
//删除单个 generateGoodsIndex.delete(new Goods(2, "张四峰","西巴 奥里给 小日本",strings, 1000D, new Date())); //删除所有 generateGoodsIndex.deleteAll(); //删除主键为?的指定 generateGoodsIndex.deleteById(3); //删除列表的所有数据 generateGoodsIndex.deleteAll(new ArrayList<Goods>());
修改信息===没有直接修改方法,得先查,再改,最后再保存
查询信息:
//无条件查询所有 generateGoodsIndex.findAll(); //查询所有并分页 generateGoodsIndex.findAll(Pageable pageable); //generateGoodsIndex.findAll(Sort sort) 查询,并排序
复杂查询{DSL查询}
查询条件:
- match:会通过分词器对查询内容进行分词,然后再通过分词进行查询。例如:搜索联想电脑,会分词成’联想’和’电脑’,再把包含’联想’和’电脑’的都查出来。
- term:不做分词,通过Keyword类型的关键字进行精确查找。例如:搜索商品id为5的商品。
- matchPhrase:不做分词,通过指定内容进行精确查找。例如:搜索联想电脑,就只查名称包含联想电脑。
- range:范围查询。例如:查询价格在5000到8000的商品。
- match 和 rang 如果同时使用,需要通过bool将二者组合起来查询。
查询常用类:
- QueryBuilders:用于构造条件对象,如match条件对象matchQuery、range条件对象rangeQuery、matchPhrase条件对象matchPhrase()、boolQuery等。
- NativeSearchQueryBuilder:用于组装条件(对象),组装后使用build()构建出查询对象NativeSearchQuery。
- HighlightBuilder:用于设置高亮的字段,需使用到它的静态内部类Field。
- FunctionScoreQueryBuilder:用于权重查询,需使用它的静态内部类FilterFunctionBuilder。
注入ES模板 — 来实现DSL查询
//注入ES模板 --- DSL查询 @Autowired private ElasticsearchRestTemplate esTemplate;
math查询:
@Test public void testA(){ //第一步:创建了个match条件的对象 --- //参数一:想要查询索引列的名称 //参数二:要查询的数据 MatchQueryBuilder matchQuery = QueryBuilders.matchQuery("goodsName", "华为手机"); //第二步:创建条件组装的构建器 NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder(); //第三步:组装条件 searchQueryBuilder.withQuery(matchQuery); //第四步:构建出条件的封装对象 NativeSearchQuery searchQuery = searchQueryBuilder.build(); //第五步:查询 //参数一:第四步创建的封装条件的对象 //参数二:返回值的泛型类 SearchHits<Goods> searchHits = esTemplate.search(searchQuery, Goods.class); //第六步:从查询结果中提取数据 --- 每个SearchHit<Goods>对象就代表从索引中查询到的一条数据 -- 而每个SearchHit又都封装了一个Goods对象 List<SearchHit<Goods>> searchHitList = searchHits.getSearchHits(); for (SearchHit<Goods> searchHit : searchHitList) { //取每个SearchHit封装的Goods对象 Goods goods = searchHit.getContent(); System.out.println(goods); } }
term关键字精确查询
@Test public void testB(){ //第一步:创建了个term条件的对象 --- //参数一:想要查询索引列的名称 //参数二:要查询的数据 TermQueryBuilder termQuery = QueryBuilders.termQuery("goodsId", 10); //通过条件组装器组装条件并返回封装了条件的对象,链式调用 NativeSearchQuery searchQuery = new NativeSearchQueryBuilder() .withQuery(termQuery) .build(); //查询 //参数一:第四步创建的封装条件的对象 //参数二:返回值的泛型类 SearchHits<Goods> searchHits = esTemplate.search(searchQuery, Goods.class); //从查询结果中提取数据 --- 每个SearchHit<Goods>对象就代表从索引中查询到的一条数据 -- 而每个SearchHit又都封装了一个Goods对象 List<SearchHit<Goods>> searchHitList = searchHits.getSearchHits(); for (SearchHit<Goods> searchHit : searchHitList) { //取每个SearchHit封装的Goods对象 Goods goods = searchHit.getContent(); System.out.println(goods); } }
多条查询 — 分词查询 范围查询 分页查询 排序
@Test public void testD(){ //创建一个match条件对象 MatchQueryBuilder matchQuery = QueryBuilders.matchQuery("goodsName", "华为小米"); //创建一个range条件的对象 --- 根据goodsPrice字段,查询商品价格在4500到5500之间的商品 RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("goodsPrice").from(4500D).to(5500D); //创建一个bool条件对象,将match条件对象和range条件的对象关联起来 BoolQueryBuilder boolQuery = QueryBuilders //创建bool条件对象 .boolQuery() //链接上边创建的match对象 .must(matchQuery) //链接上边创建的range对象 .must(rangeQuery); //创建条件组装器组装所有条件并构建出封装了所有条件的对象 NativeSearchQuery searchQuery = new NativeSearchQueryBuilder() //组装的bool条件(其实是match和range条件) .withQuery(boolQuery) //分页条件(ES分页页码从0开始) .withPageable(PageRequest.of(1, 5)) //排序条件,根据传入的列名进行排序 .withSort(SortBuilders.fieldSort("goodsPrice") //按照goodsPrice降序排序 .order(SortOrder.DESC)) .build(); //查询 SearchHits<Goods> searchHits = esTemplate.search(searchQuery, Goods.class); //从查询结果中提取数据 --- 每个SearchHit<Goods>对象就代表从索引中查询到的一条数据 -- 而每个SearchHit又都封装了一个Goods对象 List<SearchHit<Goods>> searchHitList = searchHits.getSearchHits(); for (SearchHit<Goods> searchHit : searchHitList) { //取每个SearchHit封装的Goods对象 Goods goods = searchHit.getContent(); System.out.println(goods); } }
高亮字段处理
/* 高亮处理的说明: 1)输入的内容是什么,一般就是对什么内容做高亮处理 2)高亮处理的本质就是文本两端添加了可以进行高亮显示的html的标签文本 */ @Test public void testE(){ //创建个match条件对象 MatchQueryBuilder matchQuery = QueryBuilders.matchQuery("goodsName", "华为"); /* 配置高亮字段 --- 上边match条件是按照goodsName字段,分词查询商品名称中包含华为分词的商品, 所以此处配置的高亮字段也是goodsName,且只对字段goodsName中的内容华为做高亮处理; */ HighlightBuilder.Field goodsNameField = new HighlightBuilder.Field("goodsName"); //配置需要高亮字段的前缀span标签 goodsNameField.preTags("<span style='color:red;'>"); //配置需要高亮字段的后缀span标签 goodsNameField.postTags("</span>"); //创建条件组装器并组装条件然后构建出封装了所有条件的对象 NativeSearchQuery searchQuery = new NativeSearchQueryBuilder() .withQuery(matchQuery) //组装配置的高亮字段 .withHighlightFields(goodsNameField) .build(); //查询 SearchHits<Goods> searchHits = esTemplate.search(searchQuery, Goods.class); //从查询结果中提取数据 --- 每个SearchHit<Goods>对象就代表从索引中查询到的一条数据 -- 而每个SearchHit又都封装了一个Goods对象 List<SearchHit<Goods>> searchHitList = searchHits.getSearchHits(); for (SearchHit<Goods> searchHit : searchHitList) { //取每个SearchHit封装的Goods对象 Goods goods = searchHit.getContent(); //再取出每个SearchHit进行了高亮处理的字段 String highLightGoodsName = searchHit.getHighlightField("goodsName").get(0); //使用进行了高亮处理的goodsName字段替换Goods对象中goodsName字段 goods.setGoodsName(highLightGoodsName); System.out.println(goods); } }
权重查询
@Test public void testF(){ //搜索的内容包含商品名称和描述 String keyWords = "华为发热"; //创建权重数组,根据需要搜索的内容的数量进行排序 FunctionScoreQueryBuilder.FilterFunctionBuilder[] functionBuilders = new FunctionScoreQueryBuilder.FilterFunctionBuilder[2]; //设置商品名称的权重为5 functionBuilders[0] = (new FunctionScoreQueryBuilder.FilterFunctionBuilder( QueryBuilders.matchQuery("goodsName", keyWords), ScoreFunctionBuilders.weightFactorFunction(10) )); //设置商品描述的权重为10 functionBuilders[1] = ( new FunctionScoreQueryBuilder.FilterFunctionBuilder( QueryBuilders.matchQuery("goodsDesc", keyWords), ScoreFunctionBuilders.weightFactorFunction(5) )); FunctionScoreQueryBuilder functionScoreQueryBuilder = new FunctionScoreQueryBuilder(functionBuilders); functionScoreQueryBuilder.setMinScore(2)//设置最小分数 .scoreMode(FunctionScoreQuery.ScoreMode.FIRST);//设置计分方式 //构建出查询对象NativeSearchQuery NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder() .withQuery(functionScoreQueryBuilder) .build(); //查询 SearchHits<Goods> searchHits = esTemplate.search(nativeSearchQuery, Goods.class); //提取查询结果 List<SearchHit<Goods>> searchHitList = searchHits.getSearchHits(); for (SearchHit<Goods> searchHit : searchHitList) { Goods goods = searchHit.getContent(); System.out.println(goods); } }
SpringBoot操作ES的总结:
1.环境搭建: 1>导入ES的场景启动器 2>配置文件中配置连接的ES服务器的url地址
2.用boot应用程序创建索引: 1>搞个实体类 — 映射索引 — 重点全在实体类中用到的注解
2>搞个Dao接口 — 需要继承ES场景启动器提供的一个接口ElasticsearchRepository:
1)就继承了ElasticsearchRepository接口中提供的一些操作ES索引的方法
2)我们搞的Dao接口把ElasticsearchRepository接口一继承,然后在Boot应用启动我们搞的Dao接口
加入IOC容器的时候,就会自动根据实体类给我们创建索引