Elastic Search 6.5.1 集成Java客戶端

前面瞭解了使用 HTTP 請求操作 ES,但是實際項目中操作,我們主要還是使用Java代碼操作,所以嘗試一下Java客戶端連接ES

基礎

  1. 已安裝ES,且自己能夠正常操作API,瞭解ES基本語法
  2. 本地已安裝IDE

新建springboot工程

  1. pom.xml,主要是加入ES的依賴就好,版本號與ES服務器版本號一致,我的都是6.5.1
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.elastic</groupId>
        <artifactId>es-1</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <packaging>jar</packaging>
    
        <name>es-1</name>
        <description>Demo project for Spring Boot</description>
    
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.1.1.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
    
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
            <java.version>1.8</java.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <!-- https://mvnrepository.com/artifact/org.elasticsearch.client/transport -->
            <dependency>
                <groupId>org.elasticsearch.client</groupId>
                <artifactId>transport</artifactId>
                <version>6.5.1</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>
    

     

  2. 客戶端連接服務器,通過TransportClient,這裏直接獲取連接然後注入容器
    package com.elastic.es1;
    
    import org.elasticsearch.client.transport.TransportClient;
    import org.elasticsearch.common.settings.Settings;
    import org.elasticsearch.common.transport.TransportAddress;
    import org.elasticsearch.transport.client.PreBuiltTransportClient;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    
    import java.net.InetAddress;
    import java.net.UnknownHostException;
    
    @Configuration
    @SpringBootApplication
    @ComponentScan("com.elastic.es1")
    public class Es1Application {
    
        public static void main(String[] args) {
            SpringApplication.run(Es1Application.class, args);
        }
    
        @Bean
        public TransportClient client() throws UnknownHostException {
    
            String hostName = "47.105.159.23";
            TransportAddress transportAddress = new TransportAddress(InetAddress.getByName(hostName), 9300);
    
            String clusterName = "cluster.name";
            String nodeName = "gaojie";
            Settings settings = Settings.builder().put(clusterName, nodeName).build();
            TransportClient client = new PreBuiltTransportClient(settings);
            client.addTransportAddress(transportAddress);
            return client;
        }
    
    }
    

     

  3. 編寫實體類,此處操作的是一個 employee 對象
    public class EmployeeVo {
    
        private String id;      // ID
        private String name;    // 姓名
        private String phone;   // 電話
        private Integer sex;    // 性別
        private Integer salary;  // 工資
        private String post;    // 崗位
        private String desc;    // 描述
        private Date joinTime;  // 入職時間
    
        private String keyword;     // 關鍵字
        private Integer minSalary;  // 最小工資
        private Integer maxSalary;  // 最大工資
        private Date startTime;     // 開始時間
        private Date endTime;       // 結束時間
        private Set<String> ids;    // ID集合
    
        private Object data;        // 查詢結果
        private Long total;      // 查詢記錄總數
        private Integer from;       // 起始位置
        private Integer size;       // 查詢條數
    
        public EmployeeVo(Object data, Long total) {
            this.data = data;
            this.total = total;
        }
    }

     

  4. 編寫接口類,定義方法以及常量,避免便於維護和可讀
    package com.elastic.es1.service.interfaces;
    
    import com.elastic.es1.entity.vo.EmployeeVo;
    
    import java.io.IOException;
    
    public interface EmployeeService {
    
        void save(EmployeeVo vo) throws IOException;
    
        void delete(EmployeeVo vo);
    
        EmployeeVo search(EmployeeVo vo);
    
        String INDEX = "manage";
        String TYPE = "employee";
    
        String NAME = "name";
        String PHONE = "phone";
        String SEX = "sex";
        String SALARY = "salary";
        String POST = "post";
        String DESC = "desc";
        String JOIN_TIME = "joinTime";
    
    }
    

     

  5. 方法實現(save方法,當傳入ID時爲修改,不傳ID時爲新增)
    package com.elastic.es1.service.impl;
    
    import com.elastic.es1.entity.vo.EmployeeVo;
    import com.elastic.es1.service.interfaces.EmployeeService;
    import org.elasticsearch.action.search.SearchRequestBuilder;
    import org.elasticsearch.action.search.SearchType;
    import org.elasticsearch.client.transport.TransportClient;
    import org.elasticsearch.common.xcontent.XContentBuilder;
    import org.elasticsearch.index.query.BoolQueryBuilder;
    import org.elasticsearch.index.query.QueryBuilders;
    import org.elasticsearch.index.query.RangeQueryBuilder;
    import org.elasticsearch.search.SearchHits;
    import org.elasticsearch.search.sort.SortBuilders;
    import org.elasticsearch.search.sort.SortOrder;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    
    import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
    
    @Service
    public class EmployeeServiceImpl implements EmployeeService {
    
        @Resource
        private TransportClient client;
    
        @Override
        public void save(EmployeeVo vo) throws IOException {
            XContentBuilder builder = this.getBuilder(vo);
            if (vo.getId() == null) {
                // 若不傳入 ID 則表示新增
                client.prepareIndex(INDEX, TYPE).setSource(builder).get();
            } else {
                // 若傳入 ID 則表示修改
                client.prepareUpdate(INDEX, TYPE, vo.getId()).setDoc(builder).get();
            }
        }
    
        /**
         * 將請求對象 EmployeeVo 轉換成 builder 對象
         */
        private XContentBuilder getBuilder(EmployeeVo vo) throws IOException {
            XContentBuilder builder = jsonBuilder().startObject();
            if (vo.getName() != null) {
                builder.field(NAME, vo.getName());
            }
            if (vo.getPhone() != null) {
                builder.field(PHONE, vo.getPhone());
            }
            if (vo.getPost() != null) {
                builder.field(POST, vo.getPost());
            }
            if (vo.getDesc() != null) {
                builder.field(DESC, vo.getDesc());
            }
            if (vo.getSex() != null) {
                builder.field(SEX, vo.getSex());
            }
            if (vo.getSalary() != null) {
                builder.field(SALARY, vo.getSalary());
            }
            return builder.endObject();
        }
    
        @Override
        public void delete(EmployeeVo vo) {
            if (vo.getIds() != null) {
                vo.getIds().forEach(id -> client.prepareDelete(INDEX, TYPE, id).get());
            }
        }
    
        @Override
        public EmployeeVo search(EmployeeVo vo) {
    
            // boolQuery :可以疊加多個查詢條件,相當於SQL的 AND
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            // multiMatchQuery :多字段搜索,輸入關鍵字,可以從多個字段匹配
            if (vo.getKeyword() != null) {
                boolQueryBuilder.must(QueryBuilders.multiMatchQuery(vo.getKeyword(), NAME, PHONE, POST, DESC));
            }
            // matchQuery :單字段搜索
            if (vo.getName() != null) {
                boolQueryBuilder.must(QueryBuilders.matchQuery(NAME, vo.getName()));
            }
            // wildcardQuery :通配符匹配:類似於SQL裏面的 LIKE
            if (vo.getPhone() != null) {
                boolQueryBuilder.must(QueryBuilders.wildcardQuery(PHONE, "*" + vo.getPhone() + "*"));
            }
            if (vo.getPost() != null) {
                boolQueryBuilder.must(QueryBuilders.matchQuery(POST, vo.getPost()));
            }
            if (vo.getDesc() != null) {
                boolQueryBuilder.must(QueryBuilders.matchQuery(DESC, vo.getDesc()));
            }
            // termQuery : 通常用於非字符串類型的比較,比如性別爲男的或者女的,狀態爲1或者2什麼的。。總之比較固定值
            if (vo.getSex() != null) {
                boolQueryBuilder.must(QueryBuilders.termQuery(SEX, vo.getSex()));
            }
            if (vo.getSalary() != null) {
                boolQueryBuilder.must(QueryBuilders.termQuery(SALARY, vo.getSalary()));
            }
            // rangeQuery :範圍查詢,判斷一個值是否在範圍內,比如工資大於多少,年齡多少之間,是否在有效期內。。。
            if (vo.getMinSalary() != null || vo.getMaxSalary() != null) {
                RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery(SALARY);
                if (vo.getMinSalary() != null) {
                    // from :範圍查詢裏面的下限值,包含該值
                    rangeQueryBuilder.from(vo.getMinSalary());
                }
                if (vo.getMaxSalary() != null) {
                    // to :範圍查詢裏面的上限值,包含該值
                    rangeQueryBuilder.to(vo.getMaxSalary());
                }
                boolQueryBuilder.filter(rangeQueryBuilder);
            }
            if (vo.getStartTime() != null || vo.getEndTime() != null) {
                RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery(JOIN_TIME);
                if (vo.getStartTime() != null) {
                    rangeQueryBuilder.from(vo.getStartTime());
                }
                if (vo.getEndTime() != null) {
                    rangeQueryBuilder.to(vo.getEndTime());
                }
                boolQueryBuilder.filter(rangeQueryBuilder);
            }
            SearchRequestBuilder searchRequestBuilder = client.prepareSearch(INDEX).setSearchType(SearchType.DFS_QUERY_THEN_FETCH).setQuery(boolQueryBuilder);
            // from :翻頁參數,從第幾條記錄開始
            if (vo.getFrom() != null) {
                searchRequestBuilder.setFrom(vo.getFrom());
            }
            // size :翻頁參數,查詢的記錄數
            if (vo.getSize() != null) {
                searchRequestBuilder.setSize(vo.getSize());
            }
    
            // sort : 排序規則,默認規則爲ASC升序,可以修改排序規則也可以用多個字段
            searchRequestBuilder.addSort(SortBuilders.fieldSort(SEX))
                    .addSort(SortBuilders.fieldSort(SALARY).order(SortOrder.DESC));
    
            System.out.println("查詢條件爲|" + searchRequestBuilder);
    
            // 查詢結果,由於數據都在 sourceAsMap 參數下,所以下面會再獲取 sourceAsMap 的值
            SearchHits hits = searchRequestBuilder.get().getHits();
    
            List<Map<String, Object>> data = new ArrayList<>();
            hits.forEach(hit -> {
                Map<String, Object> sourceAsMap = hit.getSourceAsMap();
                sourceAsMap.put("_id", hit.getId());
                data.add(sourceAsMap);
            });
    
            return new EmployeeVo(data, hits.totalHits);
        }
    }
    

     

  6. 編寫 Controller
    package com.elastic.es1.controller;
    
    import com.elastic.es1.entity.vo.EmployeeVo;
    import com.elastic.es1.service.interfaces.EmployeeService;
    import org.springframework.web.bind.annotation.*;
    
    import javax.annotation.Resource;
    import java.io.IOException;
    
    @RestController
    @RequestMapping("employee")
    public class EmployeeController {
    
        @Resource
        private EmployeeService employeeService;
    
        @PostMapping("save")
        public Object save(@RequestBody EmployeeVo vo) throws IOException {
            employeeService.save(vo);
            return "保存成功";
        }
    
        @DeleteMapping("delete")
        public Object delete(@RequestBody EmployeeVo vo) {
            employeeService.delete(vo);
            return  "刪除成功";
        }
    
        @GetMapping("search")
        public Object search(EmployeeVo vo) {
            return employeeService.search(vo);
        }
    
    }
    

     

  7.  修改 application.properties 端口號,因爲默認端口爲8080,防止衝突
    server.port=9090

     

項目啓動成功後,去Postman測試,都能夠正常使用,這裏只記錄一個 search 請求

GET   http://localhost:9090/employee/search?from=0&size=10
================================================
{
    "id": null,
    "name": null,
    "phone": null,
    "sex": null,
    "salary": null,
    "post": null,
    "desc": null,
    "joinTime": null,
    "keyword": null,
    "minSalary": null,
    "maxSalary": null,
    "startTime": null,
    "endTime": null,
    "ids": null,
    "data": [
        {
            "post": "設計前端",
            "phone": "18874797777",
            "sex": 1,
            "name": "桂祿",
            "dept": {
                "name": "設計中心",
                "id": "1003"
            },
            "_id": "o1ZWmGcBof4Qu3GrG81P",
            "salary": 50000,
            "join_time": "2018-05-03",
            "desc": "a front boy"
        },
        {
            "post": "架構師",
            "phone": "18874792222",
            "sex": 1,
            "name": "春哥",
            "dept": {
                "name": "技術中心",
                "id": "1001"
            },
            "_id": "nlb-l2cBof4Qu3Gr8M1Y",
            "salary": 35000,
            "join_time": "2018-03-03",
            "desc": "a framework boy"
        },
        {
            "post": "設計UI",
            "phone": "18874796666",
            "sex": 1,
            "name": "銅川",
            "dept": {
                "name": "設計中心",
                "id": "1003"
            },
            "_id": "olYDmGcBof4Qu3Grw837",
            "salary": 16000,
            "join_time": "2018-04-03",
            "desc": "a sunny boy"
        },
        {
            "post": "Java工程師",
            "phone": "18874796310",
            "sex": 1,
            "name": "高節",
            "dept": {
                "name": "技術中心",
                "id": "1001"
            },
            "_id": "nFZul2cBof4Qu3GrDc0v",
            "salary": 10000,
            "join_time": "2018-12-03",
            "desc": "a love of work boy"
        },
        {
            "post": "IOS工程師",
            "phone": "18874791111",
            "sex": 2,
            "name": "周益",
            "dept": {
                "name": "技術中心",
                "id": "1001"
            },
            "_id": "nVZ-l2cBof4Qu3GrFc1L",
            "salary": 15000,
            "join_time": "2018-10-03",
            "desc": "a IOS boy"
        },
        {
            "post": "測試工程師",
            "phone": "18874793333",
            "sex": 2,
            "name": "麗燕",
            "dept": {
                "name": "技術中心",
                "id": "1001"
            },
            "_id": "n1YAmGcBof4Qu3GrB83o",
            "salary": 12000,
            "join_time": "2018-05-03",
            "desc": "a beautiful girl"
        },
        {
            "post": "Android工程師",
            "phone": "18874794444",
            "sex": 2,
            "name": "李嶽",
            "dept": {
                "name": "技術中心",
                "id": "1001"
            },
            "_id": "oFYAmGcBof4Qu3Gr880L",
            "salary": 12000,
            "join_time": "2018-04-03",
            "desc": "a rude man"
        },
        {
            "post": "會計",
            "phone": "18874795555",
            "sex": 2,
            "name": "青萍",
            "dept": {
                "name": "財務部門",
                "id": "1002"
            },
            "_id": "oVYCmGcBof4Qu3Gr8c33",
            "salary": 6000,
            "join_time": "2018-08-03",
            "desc": "a sunny girl"
        }
    ],
    "total": 8,
    "from": null,
    "size": null
}

 

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