SpringBoot(20) 整合Elasticsearch

一、前言

本文將基於springboot 2.1.8.RELEASE 來整合 Elasticsearch

環境:elasticsearch-5.6.16

溫馨小提示: ES服務端Kibana客戶端官網下載地址: https://www.elastic.co/downloads/past-releases

二、Spring Boot 整合 Elasticsearch

1、pom.xml中引入es依賴

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

2、application.yml中配置es

spring:
  # es相關配置
  data:
    elasticsearch:
      # 配置集羣名
      cluster-name: elasticsearch   # 訪問 es服務端 `http://127.0.0.1:9200/` 填寫 `cluster_name` 對應的值
      # 配置節點信息,逗號分隔,如果沒有指定,則啓動ClientNode 【 注:9200->圖形界面端、9300->程序端 】
      cluster-nodes: 127.0.0.1:9300
      # 開啓 Elasticsearch 倉庫(默認值:true)
      repositories:
        enabled: true

3、redis和es衝突問題

如上配置後,可以先啓動一下項目,可能運行後會出現如下問題:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'elasticsearchClient' defined in class path resource [org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.elasticsearch.client.transport.TransportClient]: Factory method 'elasticsearchClient' threw exception; nested exception is java.lang.IllegalStateException: availableProcessors is already set to [8], rejecting [8]

錯誤原因:程序的其他地方使用了Netty,這裏指redis。這影響在實例化傳輸客戶端之前初始化處理器的數量。 實例化傳輸客戶端時,我們嘗試初始化處理器的數量。 由於在其他地方使用Netty,因此已經初始化並且Netty會對此進行防範,因此首次實例化會因看到的非法狀態異常而失敗。

解決:在啓動類中加上如下配置

System.setProperty("es.set.netty.runtime.available.processors","false");

在這裏插入圖片描述

注:雖然上面的方式能解決錯誤,服務可以正常啓動,但是啓動測試類時還是會報錯哦!!!

因此es配置文件中需配置在RedisConfig之前裝配,並且指定初始化時再一次添加忽略es中netty的一些配置!!!

ElasticsearchConfig 配置文件如下:

@Configuration
@AutoConfigureBefore(RedisConfig.class) // `RedisConfig.class`爲redis配置文件
public class ElasticsearchConfig {

    @PostConstruct
    void init() {
        System.setProperty("es.set.netty.runtime.available.processors", "false");
    }

    @Bean(name = "elasticsearchTemplate")
    public ElasticsearchTemplate elasticsearchTemplate(Client client, ElasticsearchConverter converter) {
        try {
            return new ElasticsearchTemplate(client, converter);
        } catch (Exception ex) {
            throw new IllegalStateException(ex);
        }
    }

    @Bean
    public ElasticsearchConverter elasticsearchConverter(
            SimpleElasticsearchMappingContext mappingContext) {
        return new MappingElasticsearchConverter(mappingContext);
    }

    @Bean
    public SimpleElasticsearchMappingContext mappingContext() {
        return new SimpleElasticsearchMappingContext();
    }

}

4、問題:failed to load elasticsearch nodes

如果出現如下問題:

failed to load elasticsearch nodes : org.elasticsearch.client.transport.NoNodeAvailableException: None of the configured nodes are available: [{#transport#-1}{6VrRZl9ISEy3MT0rx2Vd2w}{127.0.0.1}{127.0.0.1:9300}]

① 嘗試修改es服務端配置文件 network.host: 127.0.0.1
在這裏插入圖片描述
cluster-name集羣名是否一致

③ 如果檢查完以上2種情況後,還是報同樣的錯誤,就要考慮是否爲版本問題哦,小編剛開始處於新鮮感使用的是目前最新版elasticsearch-7.5.1,而spring-boot-starter-data-elasticsearch中的spring-data-elasticsearch3.1.10.RELEASE版本不支持高版本的es,因此版本選擇要注意哦!!!

三、Elasticsearch增刪改查API

1、創建索引並建立類型映射

溫馨小提示:注意包名不要導錯哦!!!

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;

/**
 * <p> 測試 </p>
 *
 * @author : zhengqing
 * @description : indexName:索引庫     type:類型(可理解爲mysql數據庫中的表名)
 * @date : 2019/12/27 14:47
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(indexName = "zq_test", type = "user")
public class User {
    @Id
    private Long id;

    @Field(type = FieldType.Keyword)
    private String name;

//    @Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_max_word")
    private String intro;

    @Field(type = FieldType.Integer)
    private Integer age;
}
@Component
public interface UserRepository extends ElasticsearchRepository<User, Long> { }
@RunWith(SpringRunner.class)
@SpringBootTest(classes = DemoApplication.class)
public class ESTest {

    @Autowired
    private ElasticsearchTemplate template;

    /**
     * 創建索引,並且建立類型映射
     */
    @Test
    public void test() throws Exception {
        // 創建索引
        template.createIndex(User.class);
        // 類型映射 - 自定義映射
        template.putMapping(User.class);
    }

}

運行後,在 http://127.0.0.1:5601/app/kibana#/dev_tools 中執行命令 GET zq_test/_mapping/user 查看類型映射

在這裏插入圖片描述

2、簡單的增刪改查

@RunWith(SpringRunner.class)
@SpringBootTest(classes = DemoApplication.class)
public class ESTest {

    @Autowired
    private UserRepository repository;

    @Test // 新增1個
    public void testAdd() throws Exception {
        User user = new User(1L, "zheng qing", "zheng qing is a programmer!", 18);
        repository.save(user);
    }

    @Test // 批量添加
    public void testBatchAdd() throws Exception {
        List<User> list = new ArrayList<>();
        for (int i = 0; i < 20; i++) {
            User user = new User(i + 2L, "zheng qing" + i + 1, "zheng qing is a programmer!", 18 + i );
            list.add(user);
        }
        repository.saveAll(list);
    }

    @Test // 獲取1個
    public void testGetOne() throws Exception {
        System.out.println(repository.findById(1L));
    }

    @Test // 獲取全部
    public void testGetAll() throws Exception {
        Iterable<User> all = repository.findAll();
        for (User user : all) {
            System.out.println(user);
        }
    }

    @Test // 新增、修改 (判斷是否有id即可~)
    public void testUpdate() throws Exception {
        Optional<User> byId = repository.findById(1L);
        User user = byId.get();
        System.out.println(user);
        user.setName("zq");
        repository.save(user);
        System.out.println(repository.findById(1L));
    }

    @Test  // 刪除
    public void testDel() throws Exception {
        repository.deleteById(1L);
        //repository.deleteAll();;
    }
    
}

3、高級查詢(過濾)+分頁+排序

@RunWith(SpringRunner.class)
@SpringBootTest(classes = DemoApplication.class)
public class ESTest {

    @Autowired
    private UserRepository repository;

    @Test // DSL查詢與過濾+分頁+排序
    public void testNativeSearchQueryBuilder() throws Exception {
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        BoolQueryBuilder bool = QueryBuilders.boolQuery();
        //模糊查詢
        bool.must(QueryBuilders.matchQuery("intro", "zheng"));
        //精確過濾
        List<QueryBuilder> filters = bool.filter();
        filters.add(QueryBuilders.rangeQuery("age").gte(0).lte(200));
        builder.withQuery(bool); //query bool must(filter)
        //排序
        builder.withSort(SortBuilders.fieldSort("age").order(SortOrder.ASC));
        //分頁   注:當前頁從0開始
        builder.withPageable(PageRequest.of(0, 10));
        //截取字段
        builder.withSourceFilter(new FetchSourceFilter(new String[]{"name", "age"}, null));
        //構造查詢條件
        NativeSearchQuery query = builder.build();
        //查詢
        Page<User> page = repository.search(query);
        System.out.println("總數:" + page.getTotalElements());
        System.out.println("總頁數:" + page.getTotalPages());
        for (User user : page.getContent()) {
            System.out.println(user);
        }
    }

}

本文案例demo源碼

https://gitee.com/zhengqingya/java-workspace

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章