先导入Elasticsearch坐标
<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
    </dependency>

1.索引操作

首先我们准备好实体类:

public class Item {
    private Long id;
    private String title; //标题
    private String category;// 分类
    private String brand; // 品牌
    private Double price; // 价格
    private String images; // 图片地址
}

我们要将实体类映射
实例:

@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; // 图片地址
}

创建索引

ElasticsearchTemplate中提供了创建索引的API:

boost 多索引容器 联合索引_Test


• 可以根据类的信息自动生成,也可以手动指定indexName和Settings映射相关的API:

boost 多索引容器 联合索引_索引_02


• 一样,可以根据类的字节码信息(注解配置)来生成映射,或者手动编写映射

我们这里采用类的字节码信息创建索引并映射:
@Test
public void createIndex() {
    // 创建索引,会根据Item类的@Document注解信息来创建
    esTemplate.createIndex(Item.class);
    // 配置映射,会根据Item类中的id、Field等字段来自动完成映射
    esTemplate.putMapping(Item.class);
}

2.删除索引

可以根据类名或索引名删除。
示例:

@Test
public void deleteIndex() {
    esTemplate.deleteIndex(Item.class);
    // 根据索引名字删除
    //esTemplate.deleteIndex("item1");
}

3.新增文档数据

我们需要定义接口(相当于dao),然后继承它就OK了。

public interface ItemRepository extends ElasticsearchRepository<Item,Long> {
}
3.1新增一个对象
@Autowired
private ItemRepository itemRepository;

@Test
public void index() {
    Item item = new Item(1L, "小米手机7", " 手机",
                         "小米", 3499.00, "http://image.baidu.com/13123.jpg");
    itemRepository.save(item);
}

去页面查询看看:

boost 多索引容器 联合索引_System_03

3.2批量新增
@Test
public void indexList() {
    List<Item> list = new ArrayList<>();
    list.add(new Item(2L, "坚果手机R1", " 手机", "锤子", 3699.00, "http://image.baidu.com/13123.jpg"));
    list.add(new Item(3L, "华为META10", " 手机", "华为", 4499.00, "http://image.baidu.com/13123.jpg"));
    // 接收对象集合,实现批量新增
    itemRepository.saveAll(list);
}

再次去页面查询:

boost 多索引容器 联合索引_System_04

4.修改

修改和新增是同一个接口,区分的依据就是id。

@Test
public void index(){
    Item item = new Item(1L, "苹果XSMax", " 手机",
            "小米", 3499.00, "http://image.baidu.com/13123.jpg");
    itemRepository.save(item);
}

查看结果:

boost 多索引容器 联合索引_Elasticsearch_05

5.查询

5.1基本查询

我们来试试查询所有:

@Test
public void query(){
    // 查询全部,并安装价格降序排序
    Iterable<Item> items = this.itemRepository.findAll(Sort.by("price").descending());
    for (Item item : items) {
        System.out.println("item = " + item);
    }
}
5.2自定义方法查询

先来看最基本的match query:

@Test
public void search(){
    // 构建查询条件
    NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
    // 添加基本分词查询
    queryBuilder.withQuery(QueryBuilders.matchQuery("title", "小米手机"));
    // 搜索,获取结果
    Page<Item> items = this.itemRepository.search(queryBuilder.build());
    // 总条数
    long total = items.getTotalElements();
    System.out.println("total = " + total);
    for (Item item : items) {
        System.out.println(item);
    }
}
5.3分页查询

利用NativeSearchQueryBuilder可以方便的实现分页:

@Test
public void searchByPage(){
    // 构建查询条件
    NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
    // 添加基本分词查询
    queryBuilder.withQuery(QueryBuilders.termQuery("category", "手机"));
    // 分页:
    int page = 0;
    int size = 2;
    queryBuilder.withPageable(PageRequest.of(page,size));
// 搜索,获取结果
Page<Item> items = this.itemRepository.search(queryBuilder.build());
// 总条数
long total = items.getTotalElements();
System.out.println("总条数 = " + total);
// 总页数
System.out.println("总页数 = " + items.getTotalPages());
// 当前页
System.out.println("当前页:" + items.getNumber());
// 每页大小
System.out.println("每页大小:" + items.getSize());

for (Item item : items) {
    System.out.println(item);
}
}

结果:

boost 多索引容器 联合索引_Elasticsearch_06

可以发现,Elasticsearch中的分页是从第0页开始。

5.4排序

排序也通用通过NativeSearchQueryBuilder完成:

@Test
public void searchAndSort(){
    // 构建查询条件
    NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
    // 添加基本分词查询
    queryBuilder.withQuery(QueryBuilders.termQuery("category", "手机"));
// 排序
queryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.ASC));

// 搜索,获取结果
Page<Item> items = this.itemRepository.search(queryBuilder.build());
// 总条数
long total = items.getTotalElements();
System.out.println("总条数 = " + total);

for (Item item : items) {
    System.out.println(item);
}
}
5.5 聚合

Elasticsearch中的聚合,包含多种类型,最常用的两种,一个叫桶,一个叫度量.
:就是对数据进行分组。
度量:分组完成以后,我们一般会对组中的数据进行聚合运算,例如求平均值、最大、最小、求和等,这些在ES中称为度量

比较常用的一些度量聚合方式:
• Avg Aggregation:求平均值
• Max Aggregation:求最大值
• Min Aggregation:求最小值
• Percentiles Aggregation:求百分比
• Stats Aggregation:同时返回avg、max、min、sum、count等
• Sum Aggregation:求和
• Top hits Aggregation:求前几
• Value Count Aggregation:求总数
• ……
注意:在ES中,需要进行聚合、排序、过滤的字段其处理方式比较特殊,因此不能被分词。这里我们将color和make这两个文字类型的字段设置为keyword类型,这个类型不会被分词,将来就可以参与聚合

5.6 嵌套聚合,求平均值

代码:

@Test
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>) this.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());
}

}

结果:

boost 多索引容器 联合索引_System_07