ElasticSearch从入门到精通--第五话(整合SpringBoot高效开发、分页高亮等、Kibana使用篇)

ElasticSearch从入门到精通–第五话(整合SpringBoot高效开发、分页高亮等、Kibana使用篇)

ElasticSearch从入门到精通–第一话(入门篇)

ElasticSearch从入门到精通–第二话(原生API调用–纯代码篇)

ElasticSearch从入门到精通–第三话(集群环境搭建篇)

ElasticSearch从入门到精通–第四话(核心概念篇)

ElasticSearch从入门到精通–第五话(整合SpringBoot高效开发、分页高亮等、Kibana使用篇)

Kibana

Kibana是一个开源的图形化管理界面,能够对Elasticsearch的数据进行可视化管理,且可在Elastic Stack中进行导航,可以完成各种操作,从跟踪查询负载,到理解请求如何流经应用都能轻松完成。

windows版7.3.0版本kibana下载(最好和es版本相同的)

  1. 下载好后,解压(解压了2个多小时。。。)

  2. 修改config/kibana.yml文件

    # 服务端口
    server.port: 5601
    # ES服务器/集群的地址
    elasticsearch.hosts: ["http://localhost:1001","http://localhost:1002","http://localhost:1003"]
    # 索引名
    kibana.index: ".kibana"
    # 编码格式
    i18n.locale: "zh-CN"
    
  3. 启动bin下的执行文件

  4. 访问http://localhost:5601

在这里插入图片描述

可到Console控制台中,直接通过json接口处理数据

在这里插入图片描述

详细kibana入门教程请看

整合Spring Data

SpringData是一个用于简化数据库、非关系数据库、索引库访问,支持云服务的开源框架。Spring Data 的使命是给各种数据访问提供统一的编程接口,不管是关系型数据库(如MySQL),还是非关系数据库(如Redis),或者类似Elasticsearch这样的索引数据库。从而简化开发人员的代码,提高开发效率。

我们要使用的就是 Spirng Data Elasticsearch模块项目。

项目特性:

  • 支持Spring的基于@Configuration的java配置方式,或者XML配置方式
  • 提供了用于操作ES的便捷工具类ElasticsearchTemplate。包括实现文档到POJO之间的自动智能映射。
    利用Spring的数据转换服务实现的功能丰富的对象映射
  • 基于注解的元数据映射方式,而且可扩展以支持更多不同的数据格式
  • 根据持久层接口自动生成对应实现方法,无需人工编写基本操作代码(类似mybatis,根据接口自动得到实现)。当然,也支持人工定制查询

那么大概也看了一下,整合SpringData后,可以使用几种方式去操作es索引,都可以使用,但是有些方法已经过时了,建议通常情况下涉及复杂业务查询时,还是使用自定义方法查询原生API查询(代码较多,未封装),有几种方式可使用(注意:引入spring-boot-starter-data-elasticsearch后,这几种方式都可以用的):

  • 使用原生API,RestHighLevelClient高级客户端,但是使用起来还是有些复杂的
  • 使用springdata提供的模板工具类ElasticsearchRestTemplate,这个直接引入就可以了(是spring容器中的组件),对这个工具类了解不多,有兴趣可以查阅资料
  • (个人推荐使用)使用继承自ElasticsearchRepository的接口类,ElasticsearchRepository类提供了一些常用的增删改查,这些增删改查的操作是指针对文档数据的,若要对索引操作,还是用上面两种方法;且我们可以在ElasticsearchRepository子接口中,像使用jpa一样,自定义方法名且不需要具体实现,springdata会帮我们自动生成实现内容(开发效率非常高,像复杂查询、高亮、分页都可以使用这种方式实现,非常好用)

集成前,注意版本

在这里插入图片描述

创建一个项目,然后引入相关依赖pom.xml

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.6.RELEASE</version>
</parent>

<properties>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>
</properties>

<dependencies>
    <!--lombock工具-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>

    <!--spring data elasticsearch-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-test</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
    </dependency>

</dependencies>

做些配置,application.yml文件

# es相关
elasticsearch:
  host: 127.0.0.1
  port: 9200
# 日志相关
logging:
  level:
    com.wlh.es: info

然后创建一个数据实体类,通过注解方式进行java类和es索引数据的双向关联

@Data
@NoArgsConstructor
@AllArgsConstructor
/**
 * indexName:索引名称
 * shards:分片数量
 * replicas:副本数,默认1
 */
@Document(indexName = "shopping", shards = 3, replicas = 1)
public class Product {
    
    

    // 标明是id主键
    @Id
    private Long id;

    /**
     * 标明是文档中的字段field
     *   type:设置字段的映射类型是text类型,那么会被分词器拆解词条
     *   analyzer:设置使用的分词器
     *   index:是否能被索引查询
     */
    @Field(type = FieldType.Text)
    private String title;

    // 设置为Keyword类型,不会被分词,是作为一个整体存在
    @Field(type = FieldType.Keyword)
    private String category;
    
    // 浮点数类型
    @Field(type = FieldType.Double)
    private Double price;

    // Keyword类型,且不能被索引查询
    @Field(type = FieldType.Keyword, index = false)
    private String images;

}

搞个es的config配置类做个配置

@Configuration
@ConfigurationProperties(prefix = "elasticsearch")
@Data
public class ElasticsearchConfig extends AbstractElasticsearchConfiguration {
    
    

    private String host;
    private Integer port;

    @Override
    public RestHighLevelClient elasticsearchClient() {
    
    
        return new RestHighLevelClient(RestClient.builder(new HttpHost(host, port)));
    }
    
}

创建个数据访问对象,可直接继承spring data es提供的,然后直接用里面的定义好的访问方法即可。

@Repository
// 有两个泛型,第一是要操作的数据对象类,第二个是序列化的id
public interface ProductDao extends ElasticsearchRepository<Product, Long> {
    
    
   
}

测试执行下试试

索引

创建索引

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringDataTest {
    
    

    @Autowired
    private ElasticsearchRestTemplate template;

    @Test
    public void createIndex() {
    
    
        // 当项目启动时,索引如果不存在则会被自动创建
        System.out.println("索引被创建啦");
    }
}

通常项目启动时,会去找数据索引类,然后去es服务器看看有没有索引,没有的话会自动创建一个索引,执行下试试。

执行完毕

在这里插入图片描述

然后去kibana看看创建的索引

在这里插入图片描述

已经创建完毕啦。

删除索引

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringDataTest {
    
    

    @Autowired
    private ElasticsearchRestTemplate template;

    @Test
    public void deleteIndex() {
    
    
        template.deleteIndex(Product.class);
        System.out.println("删除索引啦");
    }

}

deleteIndex()方法是一个过时方法了,有兴趣可以自行查阅资料。

在这里插入图片描述

文档

新增文档

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringDocTest {
    
    

    @Autowired
    private ProductDao productDao;

    /**
     * 新增文档
     */
    @Test
    public void save() {
    
    
        Product product = new Product(1L, "小米手机", "手机", 2999.99, "http://localhost/a.jpeg");
        productDao.save(product);
    }

}

执行完毕,到kibana看下数据情况

在这里插入图片描述

修改文档

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringDocTest {
    
    

    @Autowired
    private ProductDao productDao;
    /**
     * 修改文档
     * 实际只要是和文档有相同id的,继续调用save方法,即可完成修改
     */
    @Test
    public void update() {
    
    
        Product product = new Product(1L, "华为的手机", "手机", 3999.99, "http://localhost/a.jpeg");
        productDao.save(product);
    }

}

执行下,到kibana看看,数据已经变更了

在这里插入图片描述

查询文档

/**
 * 根据id查询
 */
@Test
public void getById() {
    
    
    Product product = productDao.findById(1L).get();
    System.out.println(product);
}

/**
 * 查所有
 */
@Test
public void findAll() {
    
    
    Iterable<Product> all = productDao.findAll();
    for (Product product : all) {
    
    
        System.out.println(product);
    }

}
Product(id=1, title=华为的手机, category=手机, price=3999.99, images=http://localhost/a.jpeg)

.......
Product(id=1, title=华为的手机, category=手机, price=3999.99, images=http://localhost/a.jpeg)

删除文档

@Test
public void delete() {
    
    
    Product product = new Product();
    product.setId(1L);
    productDao.delete(product);
}

批量新增

/**
 * 批量新增
 */
@Test
public void saveBatch() {
    
    
    List<Product> products = new ArrayList<>();
    for (int i = 0; i < 7; i++) {
    
    
        Product product = new Product((long) i, "【"+i+"】华为手机", "手机", 2000.00 + i, "http://localhost/a.jpeg");
        products.add(product);
    }
    productDao.saveAll(products);
}

新增完,查询一下看看

在这里插入图片描述

排序+分页查询

/**
 * 排序+分页查询
 */
@Test
public void findByPageable() {
    
    
    // 设置排序(根据id升序排序)
    Sort sort = Sort.by(Sort.Direction.ASC, "id");
    int page = 0;
    int size = 5;
    PageRequest pageRequest = PageRequest.of(page, size, sort);
    Page<Product> all = productDao.findAll(pageRequest);
    all.getContent().forEach(System.out::println);
}

结果排序+分页

Product(id=0, title=【0】华为手机, category=手机, price=2000.0, images=http://localhost/a.jpeg)
Product(id=1, title=【1】华为手机, category=手机, price=2001.0, images=http://localhost/a.jpeg)
Product(id=2, title=【2】华为手机, category=手机, price=2002.0, images=http://localhost/a.jpeg)
Product(id=3, title=【3】华为手机, category=手机, price=2003.0, images=http://localhost/a.jpeg)
Product(id=4, title=【4】华为手机, category=手机, price=2004.0, images=http://localhost/a.jpeg)

注意:上面的page为0表示是查询第一页,如果要查询第二页数据,那么page=1

自定义查询

继承自ElasticsearchRepository类后,能继承一些基本的索引、文档的操作,但是涉及到复杂查询时,我们就需要去自定义一些查询了

自定义查询的方式挺多,简单介绍下类似jpa方式的查询,在继承ElasticsearchRepository的子接口中,定义相关的方法即可。

条件查询

在这里插入图片描述

并且在编写方法名称时,会自动提示,用起来嘎嘎爽。

接口层方法

@Repository
public interface ProductDao extends ElasticsearchRepository<Product, Long> {
    
    

    List<Product> findByTitle(String title);

}

处理层

@Test
public void termQuery() {
    
    
    List<Product> products = productDao.findByTitle("为华");
    products.forEach(System.out::println);
}

结果

Product(id=5, title=【5】华为手机, category=手机, price=2005.0, images=http://localhost/a.jpeg)
Product(id=0, title=【0】华为手机, category=手机, price=2000.0, images=http://localhost/a.jpeg)
Product(id=2, title=【2】华为手机, category=手机, price=2002.0, images=http://localhost/a.jpeg)
Product(id=3, title=【3】华为手机, category=手机, price=2003.0, images=http://localhost/a.jpeg)
Product(id=4, title=【4】华为手机, category=手机, price=2004.0, images=http://localhost/a.jpeg)
Product(id=1, title=【1】华为手机, category=手机, price=2001.0, images=http://localhost/a.jpeg)
Product(id=6, title=【6】华为手机, category=手机, price=2006.0, images=http://localhost/a.jpeg)

并且有分词器的存在,查询时,虽然是写的为华,但是查询时,会将为华拆解为为、华,然后去倒排表中查询,所有匹配到的数据都会被查询出来。

条件+分页+排序查询

接口层

Page<Product> findByTitleOrderByIdAsc(String title, Pageable pageable);

处理层

要注意:es这边分页查询时,页数从0开始的

@Test
public void query() {
    
    
    PageRequest pageRequest = PageRequest.of(1, 5);
    Page<Product> order = productDao.findByTitleOrderByIdAsc("华", pageRequest);
    order.forEach(System.out::println);
}

结果

Product(id=5, title=【5】华为手机, category=手机, price=2005.0, images=http://localhost/a.jpeg)
Product(id=6, title=【6】华为手机, category=手机, price=2006.0, images=http://localhost/a.jpeg)

过多不再介绍,遇到复杂的业务场景时,可以查阅官方文档

自定义查询官方文档定位

高亮查询❤

这个处理起来也比较简单了,先给个官方地址吧,方便查阅,高亮查询注解版

接口层,一个@Highligh注解搞定,注意配置高亮标签参数

@Highlight(fields = {
    
    
    @HighlightField(name = "title")},
           parameters = 
           @HighlightParameters(preTags = "<strong><font style='color:red'>", postTags = "</font></strong>", fragmentSize = 500, numberOfFragments = 3)
          )
SearchPage<Product> findByTitleOrderByIdAsc(String title, Pageable pageable);

处理层

@Test
public void query() {
    
    
    PageRequest pageRequest = PageRequest.of(1, 5);
    SearchPage<Product> productSearchPage = productDao.findByTitleOrderByIdAsc("华", pageRequest);
    productSearchPage.getSearchHits().forEach(System.out::println);
}

高亮字段在highlightFields中

SearchHit{id='5', score=NaN, sortValues=[5], content=Product(id=5, title=【5】华为手机, category=手机, price=2005.0, images=http://localhost/a.jpeg), highlightFields={title=[【5】<font style='color:red'>华</font>为手机]}}
SearchHit{id='6', score=NaN, sortValues=[6], content=Product(id=6, title=【6】华为手机, category=手机, price=2006.0, images=http://localhost/a.jpeg), highlightFields={title=[【6】<font style='color:red'>华</font>为手机]}}

如果查询时,不进行分页,那么Dao这么写

@SuppressWarnings("SpringDataRepositoryMethodReturnTypeInspection")	// 压制警告
@Highlight(fields = {
    
    
    @HighlightField(name = "title")},
           parameters =
           @HighlightParameters(preTags = "<font style='color:red'>", postTags = "</font>", fragmentSize = 500, numberOfFragments = 3)
          )
List<SearchHit<Product>> findByTitle(String title);
// 或这么写
SearchHits<Product> findByTitle(String title);

猜你喜欢

转载自blog.csdn.net/weixin_45248492/article/details/127781979