整合常用技術框架之 Elasticsearch

利用 Spring Boot 整合 ES

Elasticsearch(簡稱 ES),是一個全文搜索引擎,同時可以作爲 NoSQL 數據庫,存儲任意格式的文檔和數據,也可以用於大數據的分析與統計。

ES是 Apache 開源的產品,其主要具有以下特點:

  1. 以 Lucene 爲底層進行封裝,爲用戶提供了一套簡單、易用、風格一致的 RESTful 風格的 API 接口;
  2. 它以一種分佈式的搜索引擎架構爲用戶提供服務,可以很容易的擴展到上百個節點,甚至更多,使系統具備高可用、高併發等特性;
  3. 支持 PB 級別數據查詢,其主要用於大數據的查詢、搜索、統計分析等。

通常用來操作 ES 的客戶端有如下幾種:

  1. TransportClient
  2. JestClient
  3. Spring Data Elasticsearch
  4. HttpClient

其中 HttpClient 主要是利用 ES 的原生 API 對其進行操作,在開發中不是太靈活,因此通常情況下不會選擇其對 ES 進行操作。

利用 TransportClient、Spring Data Elasticsearch 對 ES 操作很方便。但隨着 ES 版本的變更,相關的 API 也在不斷的調整,因此有 ES 服務端版本變更之後,客戶端的代碼也要隨之進行重新編寫。

JestClient 對 ES 進行了封裝,填補了 ES 在 HTTP Rest 接口客戶端上的空白,它適用於 ES 2.0 以上的版本,無需因爲 ES 服務端版本更改而對代碼進行修改。本文我們將重要講解 JestClient 客戶端對 ES 的操作。

利用 JestClient 作爲客戶端對 ES 進行操作

該操作過程主要包括9步,接下來我們一一做下講解。

1. 在 pom 文件中添加依賴,代碼如下:

 <dependency>
    <groupId>io.searchbox</groupId>
    <artifactId>jest</artifactId>
    <version>5.3.3</version>
</dependency>

<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>6.3.0</version>
</dependency>

2. 在 application.yml 配置文件中添加 ES 連接配置信息,代碼如下:

spring:
  elasticsearch:
    jest:
      url: http://******:9200
      username: ***
      password: *****
      readTimeout: 20000
      connectionTimeout: 20000

3. 讀取配置信息:

@Configuration
@ConfigurationProperties(prefix = "spring.elasticsearch.jest")
public class EsClientConfiguration {
    /**
     * ES連接url
     */
    private String url;

    /**
     * ES連接用戶名
     */
    private String username;

    /**
     * ES連接用密碼
     */
    private String password;

    /**
     * ES 讀取超時時間
     */
    private Integer readTimeout;

    /**
     * ES連接超時時間
     */
    private Integer connectionTimeout;

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Integer getReadTimeout() {
        return readTimeout;
    }

    public void setReadTimeout(Integer readTimeout) {
        this.readTimeout = readTimeout;
    }

    public Integer getConnectionTimeout() {
        return connectionTimeout;
    }

    public void setConnectionTimeout(Integer connectionTimeout) {
        this.connectionTimeout = connectionTimeout;
    }
}

4. 添加獲取 JestClient 實例工具類:

@Component
public class JestClientUtil {
    @Autowired
    private EsClientConfiguration esClientConfig;

    private JestClient jestClient = null;

    public JestClient createJestClient() {
        if (jestClient == null) {
            synchronized (this) {
                if (jestClient == null) {
                    JestClientFactory factory = new JestClientFactory();
                    factory.setHttpClientConfig(new HttpClientConfig

//設置連接es server url地址
.Builder(esClientConfig.getUrl())

//設置連接es用戶名
.defaultCredentials(esClientConfig.getUsername()

//設置連接es密碼
esClientConfig.getPassword())

//開啓多線程模式
.multiThreaded(true)

//設置連接es最大超時時間
.connTimeout(esClientConfig.getConnectionTimeout())

//設置從es讀取數據最大時間
.readTimeout(esClientConfig.getReadTimeout())

.build());

                    jestClient = factory.getObject();
                }
            }
        }

        return jestClient;
    }
}

5. 新建持久層 StudentRepository 接口:

public interface StudentRepository {
    /**
     * 添加學生
     *
     * @param student
     */
    void addStudent(Student student);

    /**
     * 批量添加學生
     *
     * @param students
     */
    void batchAddStudent(List<Student> students);

    /**
     * 根據學生信息查詢學生信息
     *
     * @param studentName
     */
    List<Student> queryStudentByName(String studentName);

    /**
     * 創建索引
     */
    public void createIndex();
}

6. 新建持久層實現類 StudentRepositoryImpl:

@Repository("studentDao")
public class StudentRepositoryImpl implements StudentRepository {
    //es 索引名稱
    private static final String ES_INDEX_NAME = "student_index";
    //es type名稱
    private static final String ES_TYPE_NAME = "student_type";

    @Autowired
    private JestClientUtil jestClientUtil;

    //向索引中添加學生信息
    @Override
    public void addStudent(Student student) {
        Index index = new Index.Builder(student).index(this.ES_INDEX_NAME).
                type(this.ES_TYPE_NAME).build();
        try {
            //獲取jestClient實例並向索引插入學生信息
            JestResult jestResult = jestClientUtil.createJestClient().execute(index);

            System.out.println(jestResult.isSucceeded());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //批量添加學生信息
    @Override
    public void batchAddStudent(List<Student> students) {
        if (!CollectionUtils.isEmpty(students)) {
            try {
                Bulk.Builder bulk = new Bulk.Builder().defaultIndex(this.ES_INDEX_NAME).
                        defaultType(this.ES_TYPE_NAME);
                //將學生列表信息循環假如bulk桶中
                for (Student student : students) {
                    Index index = new Index.Builder(student).build();
                    bulk.addAction(index);
                }

//獲取jestClient實例並向index中插入學生信息
jestClientUtil.createJestClient().execute(bulk.build());
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
    }

    //根據學生姓名查詢學生信息
    @Override
    public List<Student> queryStudentByName(String studentName) {
        //實例化SearchSourceBuilder對象
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

//組裝index 查詢條件
searchSourceBuilder.query(QueryBuilders.matchQuery("name", studentName));

        //利用SearchSourceBuilder對象構建index查詢對象
        Search search = new Search.Builder(searchSourceBuilder.toString())
                .addIndex(this.ES_INDEX_NAME).addType(this.ES_TYPE_NAME).build();
        try {
            //獲取jestClient實例並向對index執行查詢語句 
            JestResult result = jestClientUtil.createJestClient().execute(search);
            //獲取查詢結果
            return result.getSourceAsObjectList(Student.class);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    //創建es索引
    @Override
    public void createIndex() {
        try {
            jestClientUtil.createJestClient().execute(new CreateIndex.
                    Builder(this.ES_INDEX_NAME).build());
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}

7. 新建服務層接口 StudentService 及其實現類 StudentServiceImpl:

public interface StudentService {
    /**
     * 添加學生信息
     * @param student
     * @return
     */
    void addStudent(Student student);

    /**
     * 批量添加學生信息
     * @param students
     * @return
     */
    void batchAddStudent(List<Student> students);


    /**
     * 根據學生姓名查詢學生列表信息
     * @param studentName
     * @return
     */
    List<Student> queryStudentsByName(String studentName);

    /**
     * 創建索引
     */
    public void createIndex();
}

//定義學生信息服務接口實現類
@Service("studentService")
public class StudentServiceImpl implements StudentService {

    @Resource(name = "studentDao")
    private StudentRepository studentDao;

    //添加學生信息
    @Override
    public void addStudent(Student student) {
        studentDao.addStudent(student);
    }

    //批量添加學生信息
    @Override
    public void batchAddStudent(List<Student> students) {
    studentDao.batchAddStudent(students);
    }

    //根據學生姓名查詢學生信息
    @Override
    public List<Student> queryStudentsByName(String studentName) {
        return studentDao.queryStudentByName(studentName);
    }

    //創建es索引
    @Override
    public void createIndex() {
        studentDao.createIndex();
    }
}

8. 新建控制層 EsClientController:

//控制器定義
@RequestMapping("/esClient")
@RestController
public class EsClientController {
    @Autowired
    private StudentService studentService;

    //添加學生信息
    @RequestMapping("/addStudent")
    public String addStudent(String studentName, Integer age) {
        Student student = new Student(UUID.randomUUID().toString(),
                studentName, age, new Date());

        studentService.addStudent(student);

        return "success";
    }

    //批量添加學生信息
    @RequestMapping("/batchAddStudent")
    public String batchAddStudent() {
        for (int i = 0; i < 100; i++) {
            Student student = new Student(UUID.randomUUID().toString(),
                    "黃家駒" + i, i + 1, new Date());
            studentService.addStudent(student);
        }

        return "success";
    }

    //根據學生姓名查詢學生信息
    @RequestMapping("/queryStudentsWithName")
    public List<Student> queryStudentsByName(String studentName) {
        return studentService.queryStudentsByName(studentName);
    }

    //創建es索引
    @RequestMapping("/createIndex")
    public String queryStudentsByName() {
        studentService.createIndex();
        return "Success";
    }
}

9. 啓動程序,利用 Postman 對新建索引,新增學生信息,查詢學生信息接口分別進行測試。

(1)創建索引。

enter image description here

(2)新增學生信息。

enter image description here

(3)根據姓名查詢學生信息。

enter image description here

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