知识点
ES全名Elasticsearch
,功能是搜索功能,跟他同款的有个Solr
,都是基于Lucene
封装的数据库,他们都是数据库,都是需要先在本地安装数据库,然后往里面存,再按要求取的整个过程
es7.x和6.x区别很大,看准学习7.x的
文章来自
Repository
Repository,高亮
Template,高亮
狂神说,高亮
下载安装
- 查看【ELK/安装】笔记,安装上ES就行,另外两个不需要安装
整合Java
- maven依赖
<properties>
<java.version>1.8</java.version>
<elasticsearch.version>7.6.1</elasticsearch.version>
</properties>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
- 配置,不能用文件的配置
@Configuration
public class conf {
@Bean
RestHighLevelClient elasticsearchClient() {
ClientConfiguration configuration = ClientConfiguration.builder()
.connectedTo("localhost:9200")
//.withConnectTimeout(Duration.ofSeconds(5))
//.withSocketTimeout(Duration.ofSeconds(3))
//.useSsl()
//.withDefaultHeaders(defaultHeaders)
//.withBasicAuth(username, password)
// ... other options
.build();
RestHighLevelClient client = RestClients.create(configuration).rest();
return client;
}
}
- 创建bean
/**
* 加上了@Document注解之后,默认情况下这个实体中所有的属性都会被建立索引、并且分词
* index:是否设置索引, store是否存储数据,type:数据类型,analyzer:分词粒度选择,searchAnalyzer:查询进行分词处理
* ik_smart:进行最小粒度分词,ik_max_word进行最大粒度分词
*
*/
@Document(indexName = "item",type = "docs", shards = 1, replicas = 0)
public class Item {
@Id
private Long id;
@Field(type = FieldType.Text, analyzer = "ik_max_word")
private String title; //标题
@Field(type = FieldType.Keyword)
private String category;// 分类
@Field(type = FieldType.Keyword)
private String brand; // 品牌
@Field(type = FieldType.Double)
private Double price; // 价格
@Field(index = false, type = FieldType.Keyword)
private String images; // 图片地址
对es的操作有三种方式
- 使用template / ElasticsearchRestTemplate
- 使用repository
- 使用client / restHighLevelClient
这里主要使用的是repository 和 restHighLevelClient
创建索引和映射
public class ElasticSearctTest {
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
@Test
public void testCreate() {
// 创建索引,会根据Item类的@Document注解信息来创建
elasticsearchTemplate.createIndex(Item.class);
// 配置映射,会根据Item类中的id、Field等字段来自动完成映射
elasticsearchTemplate.putMapping(Item.class);
}
}
简单操作,类似于MybatisPlus的MapperDao接口
public interface ItemRepository extends ElasticsearchRepository<Item,Long> {
// 留空
}
public class ES {
@Autowired
private ItemRepository itemRepository;
public void testAdd() {
Item item = new Item(1L, "小米手机7", " 手机",
"小米", 3499.00, "http://image.leyou.com/13123.jpg");
itemRepository.save(item);
}
// 修改(id存在就是修改,否则就是插入)
public void testUpdate() {
Item item = new Item(1L, "小米手机7777", " 手机",
"小米", 9499.00, "http://image.leyou.com/13123.jpg");
itemRepository.save(item);
}
public void indexList() {
List<Item> list = new ArrayList<>();
list.add(new Item(2L, "坚果手机R1", " 手机", "锤子", 3699.00, "http://image.leyou.com/123.jpg"));
list.add(new Item(3L, "华为META10", " 手机", "华为", 4499.00, "http://image.leyou.com/3.jpg"));
// 接收对象集合,实现批量新增
itemRepository.saveAll(list);
}
public void testDelete() {
itemRepository.deleteById(1L);
}
public void testQuery(){
Optional<Item> optional = itemRepository.findById(2L);
System.out.println(optional.get());
}
public void testFind(){
// 查询全部,并按照价格降序排序
Iterable<Item> items = this.itemRepository.findAll(Sort.by(Sort.Direction.DESC, "price"));
items.forEach(item-> System.out.println(item));
}
}
简单操作之自定义方法,通过规定的方法名创建方式就行,方法名的创建方式查看最上面的原文,或者百度
public interface ItemRepository extends ElasticsearchRepository<Item,Long> {
/**
* 根据价格区间查询
* @param price1
* @param price2
* @return
*/
List<Item> findByPriceBetween(double price1, double price2);
}
public class ES {
@Autowired
private ItemRepository itemRepository;
public void queryByPriceBetween(){
List<Item> list = this.itemRepository.findByPriceBetween(2000.00, 3500.00);
for (Item item : list) {
System.out.println("item = " + item);
}
}
}
复杂操作
public class ES {
@Autowired
private ItemRepository itemRepository;
// SearchSourceBuilder 条件构造
// HighlightBuilder 构建高亮
// TermQueryBuilder 精确查询
// MatchAllQueryBuilder
public void testBaseQuery(){
// 词条查询
MatchQueryBuilder queryBuilder = QueryBuilders.matchQuery("title", "小米");
// 执行查询
Iterable<Item> items = itemRepository.search(queryBuilder);
items.forEach(System.out::println);
}
public void testNativeQuery(){
// 构建查询条件
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
// 添加基本的分词查询
queryBuilder.withQuery(QueryBuilders.matchQuery("title", "小米"));
// 执行搜索,获取结果
Page<Item> items = itemRepository.search(queryBuilder.build());
// 打印总条数
System.out.println(items.getTotalElements());
// 打印总页数
System.out.println(items.getTotalPages());
items.forEach(System.out::println);
}
public void testNativeQuery2(){
// 构建查询条件
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
// 添加基本的分词查询
queryBuilder.withQuery(QueryBuilders.termQuery("category", "手机"));
// 初始化分页参数
int page = 0;
int size = 3;
// 设置分页参数
queryBuilder.withPageable(PageRequest.of(page, size));
// 执行搜索,获取结果
Page<Item> items = itemRepository.search(queryBuilder.build());
// 打印总条数
System.out.println(items.getTotalElements());
// 打印总页数
System.out.println(items.getTotalPages());
// 每页大小
System.out.println(items.getSize());
// 当前页
System.out.println(items.getNumber());
items.forEach(System.out::println);
}
public void testSort(){
// 构建查询条件
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
// 添加基本的分词查询
queryBuilder.withQuery(QueryBuilders.termQuery("category", "手机"));
// 排序
queryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.DESC));
// 执行搜索,获取结果
Page<Item> items = itemRepository.search(queryBuilder.build());
// 打印总条数
System.out.println(items.getTotalElements());
items.forEach(System.out::println);
}
public void testAgg(){
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
// 不查询任何结果
queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{""}, null));
// 1、添加一个新的聚合,聚合类型为terms,聚合名称为brands,聚合字段为brand
queryBuilder.addAggregation(
AggregationBuilders.terms("brands").field("brand"));
// 2、查询,需要把结果强转为AggregatedPage类型
AggregatedPage<Item> aggPage = (AggregatedPage<Item>) itemRepository.search(queryBuilder.build());
// 3、解析
// 3.1、从结果中取出名为brands的那个聚合,
// 因为是利用String类型字段来进行的term聚合,所以结果要强转为StringTerm类型
StringTerms agg = (StringTerms) aggPage.getAggregation("brands");
// 3.2、获取桶
List<StringTerms.Bucket> buckets = agg.getBuckets();
// 3.3、遍历
for (StringTerms.Bucket bucket : buckets) {
// 3.4、获取桶中的key,即品牌名称
System.out.println(bucket.getKeyAsString());
// 3.5、获取桶中的文档数量
System.out.println(bucket.getDocCount());
}
}
public void testSubAgg(){
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
// 不查询任何结果
queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{""}, null));
// 1、添加一个新的聚合,聚合类型为terms,聚合名称为brands,聚合字段为brand
queryBuilder.addAggregation(
AggregationBuilders.terms("brands").field("brand")
.subAggregation(AggregationBuilders.avg("priceAvg").field("price")) // 在品牌聚合桶内进行嵌套聚合,求平均值
);
// 2、查询,需要把结果强转为AggregatedPage类型
AggregatedPage<Item> aggPage = (AggregatedPage<Item>) itemRepository.search(queryBuilder.build());
// 3、解析
// 3.1、从结果中取出名为brands的那个聚合,
// 因为是利用String类型字段来进行的term聚合,所以结果要强转为StringTerm类型
StringTerms agg = (StringTerms) aggPage.getAggregation("brands");
// 3.2、获取桶
List<StringTerms.Bucket> buckets = agg.getBuckets();
// 3.3、遍历
for (StringTerms.Bucket bucket : buckets) {
// 3.4、获取桶中的key,即品牌名称 3.5、获取桶中的文档数量
System.out.println(bucket.getKeyAsString() + ",共" + bucket.getDocCount() + "台");
// 3.6.获取子聚合结果:
InternalAvg avg = (InternalAvg) bucket.getAggregations().asMap().get("priceAvg");
System.out.println("平均售价:" + avg.getValue());
}
}
}
高亮搜索
public class ES {
@Resource
private RestHighLevelClient restHighLevelClient;
@RequestMapping("/highlight")
public List highlight(@RequestParam("search") String search) throws IOException {
SearchRequest searchRequest = new SearchRequest();
//搜索体(可以添加多个搜索参数)
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
QueryStringQueryBuilder queryBuilder = new QueryStringQueryBuilder(search);
queryBuilder.field("title");
//构建高亮体
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("title");
highlightBuilder.preTags("<span style="color:red">");
highlightBuilder.postTags("</span>");
// highlightBuilder.requireFieldMatch(false);
//搜索体(添加多个搜索参数)
searchSourceBuilder.highlighter(highlightBuilder);
searchSourceBuilder.query(queryBuilder);
searchSourceBuilder.from(1).size(10);
searchRequest.source(searchSourceBuilder);
//执行查询
SearchResponse searchResponse = restHighLevelClient.search(searchRequest,RequestOptions.DEFAULT);
//获取搜索的文档结果
List<Map<String,Object>> list = new ArrayList<>();
for (SearchHit documentFields : searchResponse.getHits().getHits()) {
Map<String, HighlightField> highlightFields = documentFields.getHighlightFields();
HighlightField title = highlightFields.get("title");
Map<String, Object> sourceAsMap = documentFields.getSourceAsMap();
sourceAsMap.put("title",title);
System.out.println(title);
list.add(sourceAsMap);
}
return list;
}
}
同款