SpringBoot整合ElasticSearch

Java客戶端

在Elasticsearch中,爲java提供了2種客戶端,一種是REST風格的客戶端,另外一種是Java API的客戶端。https://www.elastic.co/guide/...html

1.REST客戶端
Elasticsearch提供了2種REST客戶端,一種是低級客戶端,一種是高級客戶端。java

  • Java Low Level REST Client:官方提供的低級客戶端。該客戶端經過http來鏈接Elasticsearch集羣。用戶在使用該客戶端時須要將請求數據手動拼接成Elasticsearch所需JSON格式進行發送,收到響應時一樣也須要將返回的JSON數據手動封裝成對象。雖然麻煩,不過該客戶端兼容全部的Elasticsearch版本。
  • Java High Level REST Client:官方提供的高級客戶端。該客戶端基於低級客戶端實現,它提供了不少便捷的API來解決低級客戶端須要手動轉換數據格式的問題。

2.構造數據node

curl -X POST "http://47.101.129.45:9200/test/house/_bulk?pretty" -H 'Content-Type: application/json' --data-binary '
{"index":{"_index":"test","_type":"house"}}
{"id":"1001","title":"整租 · 南丹大樓 1居室 7500","price":"7500"}
{"index":{"_index":"test","_type":"house"}}
{"id":"1002","title":"陸家嘴板塊,精裝設計一室一廳,可拎包入住誠意租。","price":"8500"}
{"index":{"_index":"test","_type":"house"}}
{"id":"1003","title":"整租 · 健安坊 1居室 4050","price":"7500"}
{"index":{"_index":"test","_type":"house"}}
{"id":"1004","title":"整租 · 中凱城市之光+視野開闊+景色秀麗+拎包入住","price":"6500"}
{"index":{"_index":"test","_type":"house"}}
{"id":"1005","title":"整租 · 南京西路品質小區 21213三軌交匯配套齊* 拎包入住","price":"6000"}
{"index":{"_index":"test","_type":"house"}}
{"id":"1006","title":"祥康裏簡約風格 *南戶型拎包入住看房隨時","price":"7000"}
'

1.jpg

3.REST低級客戶端
1)用IDEA建立SpringBoot工程spring-elasticsearchmysql

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>elasticsearch</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-client</artifactId>
            <version>6.5.4</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.4</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2)編寫測試web

/**
 * REST低級客戶端
 */
public class TestElasticSearch {
    private static final ObjectMapper MAPPER = new ObjectMapper();

    private RestClient restClient;

    @Before
    public void init() {
        RestClientBuilder restClientBuilder = RestClient.builder(
                new HttpHost("47.101.129.45", 9200, "http"));
        restClientBuilder.setFailureListener(new RestClient.FailureListener() {
            @Override
            public void onFailure(Node node) {
                System.out.println("出錯了 -> " + node);
            }
        });
        this.restClient = restClientBuilder.build();
    }

    @After
    public void after() throws IOException {
        restClient.close();
    }

    /**
     * 查詢集羣狀態
     *
     * @throws IOException
     */
    @Test
    public void testGetInfo() throws IOException {
        Request request = new Request("GET", "/_cluster/state");
        request.addParameter("pretty", "true");
        Response response = this.restClient.performRequest(request);
        System.out.println(response.getStatusLine());
        System.out.println(EntityUtils.toString(response.getEntity()));
    }

    /**
     * 新增數據
     *
     * @throws IOException
     */
    @Test
    public void testCreateData() throws IOException {
        Request request = new Request("POST", "/test/house");
        request.addParameter("pretty", "true");

        Map<String, Object> data = new HashMap<>();
        data.put("id", "2001");
        data.put("title", "張江高科");
        data.put("price", "3500");
        request.setJsonEntity(MAPPER.writeValueAsString(data));
        Response response = this.restClient.performRequest(request);

        System.out.println(response.getStatusLine());
        System.out.println(EntityUtils.toString(response.getEntity()));
    }

    /**
     * 根據id查詢數據
     */
    @Test
    public void testQueryData() throws IOException {
        Request request = new Request("GET", "/test/house/3xNNOW4BpJzEX51okOM5");
        request.addParameter("pretty", "true");

        Response response = this.restClient.performRequest(request);
        System.out.println(response.getStatusLine());
        System.out.println(EntityUtils.toString(response.getEntity()));
    }

    /**
     * 搜索數據
     */
    @Test
    public void testSearchData() throws IOException {
        Request request = new Request("POST", "/test/house/_search");
        String searchJson = "{\"query\": {\"match\": {\"title\": \"拎包入住\"}}}";
        request.setJsonEntity(searchJson);
        request.addParameter("pretty", "true");
        Response response = this.restClient.performRequest(request);

        System.out.println(response.getStatusLine());
        System.out.println(EntityUtils.toString(response.getEntity()));
    }
}

從使用中,能夠看出,基本和咱們使用RESTful api使用幾乎是一致的spring

4.REST高級客戶端
pom.xml引入依賴sql

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>6.5.4</version>
</dependency>

編寫測試docker

/**
 * REST高級客戶端
 */
public class TestRestHighLevel {

    private RestHighLevelClient client;

    @Before
    public void init() {
        RestClientBuilder restClientBuilder = RestClient.builder(
                new HttpHost("47.101.129.45", 9200, "http")
        );

        this.client = new RestHighLevelClient(restClientBuilder);
    }

    @After
    public void after() throws Exception {
        this.client.close();
    }

    /**
     * 新增文檔,同步操做
     *
     * @throws Exception
     */
    @Test
    public void testCreate() throws Exception {
        Map<String, Object> data = new HashMap<>();
        data.put("id", "2002");
        data.put("title", "南京西路 拎包入住 一室一廳");
        data.put("price", "4500");

        IndexRequest indexRequest = new IndexRequest("test", "house").source(data);

        IndexResponse indexResponse = this.client.index(indexRequest, RequestOptions.DEFAULT);

        System.out.println(indexResponse);
        System.out.println("id->" + indexResponse.getId());
        System.out.println("index->" + indexResponse.getIndex());
        System.out.println("type->" + indexResponse.getType());
        System.out.println("version->" + indexResponse.getVersion());
        System.out.println("result->" + indexResponse.getResult());
        System.out.println("shardInfo->" + indexResponse.getShardInfo());
    }

    /**
     * 新增文檔,異步操做
     */

    @Test
    public void testCreateAsync() throws Exception {
        Map<String, Object> data = new HashMap<>();
        data.put("id", "2003");
        data.put("title", "南京東路最新房源二室一廳");
        data.put("price", "5500");

        IndexRequest indexRequest = new IndexRequest("test", "house").source(data);

        this.client.indexAsync(indexRequest, RequestOptions.DEFAULT, new ActionListener<IndexResponse>() {
            @Override
            public void onResponse(IndexResponse indexResponse) {
                System.out.println(indexResponse);
            }

            @Override
            public void onFailure(Exception e) {
                System.out.println(e);
            }
        });
        Thread.sleep(2000);
    }

    /**
     * 指定返回字段查詢
     */

    @Test
    public void testQuery() throws Exception {
        GetRequest request = new GetRequest("test", "house", "4hN-OW4BpJzEX51oe-Of");

        //指定返回字段
        String[] includes = new String[]{"title", "id"};
        String[] excludes = Strings.EMPTY_ARRAY;

        FetchSourceContext fetchSourceContext = new FetchSourceContext(true, includes, excludes);
        request.fetchSourceContext(fetchSourceContext);

        GetResponse response = this.client.get(request, RequestOptions.DEFAULT);
        System.out.println("數據 -> " + response);
    }

    /**
     * 判斷是否存在
     */

    @Test
    public void testExists() throws Exception {
        GetRequest getRequest = new GetRequest("test", "house", "4hN-OW4BpJzEX51oe-Of");
        //不返回字段
        getRequest.fetchSourceContext(new FetchSourceContext(false));
        boolean exists = this.client.exists(getRequest, RequestOptions.DEFAULT);
        System.out.println("exists -> " + exists);
    }

    /**
     * 刪除數據
     */
    @Test
    public void testDelete() throws Exception {
        DeleteRequest deleteRequest = new DeleteRequest("test", "house", "4hN-OW4BpJzEX51oe-Of");
        DeleteResponse response = this.client.delete(deleteRequest, RequestOptions.DEFAULT);
        System.out.println(response.status());// OK or NOT_FOUND
    }

    /**
     * 更新數據
     */
    @Test
    public void testUpdate() throws Exception {
        UpdateRequest updateRequest = new UpdateRequest("test", "house", "4BN4OW4BpJzEX51o3-PZ");

        Map<String, Object> data = new HashMap<>();
        data.put("title", "南京西路2 一室一廳2");
        data.put("price", "4000");
        updateRequest.doc(data);
        UpdateResponse response = this.client.update(updateRequest, RequestOptions.DEFAULT);
        System.out.println("version -> " + response.getVersion());
    }

    /**
     * 查詢數據
     */
    @Test
    public void testSearch() throws Exception {
        SearchRequest searchRequest = new SearchRequest("test");
        searchRequest.types("house");

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(QueryBuilders.matchQuery("title", "拎包入住"));
        sourceBuilder.from(0);
        sourceBuilder.size(5);
        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
        searchRequest.source(sourceBuilder);

        SearchResponse search = this.client.search(searchRequest, RequestOptions.DEFAULT);
        System.out.println("搜索到->" + search.getHits().totalHits + "條數據");

        SearchHits hits = search.getHits();
        for (SearchHit hit : hits) {
            System.out.println(hit.getSourceAsString());
        }
    }

}

SpringBoot整合Elasticsearch

Spring Data項目對Elasticsearch作了支持,其目的就是簡化對Elasticsearch的操做,https://spring.io/projects/sp...apache

1.導入依賴json

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>elasticsearch</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-client</artifactId>
            <version>6.5.4</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.4</version>
        </dependency>

        <!--REST高級客戶端-->
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>6.5.4</version>
        </dependency>

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

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2.編寫application.yml

spring:
  application:
    name: spring-elasticsearch
  data:
    elasticsearch:
      cluster-name: docker-cluster
      cluster-nodes: 47.101.129.45:9300

這裏要注意,使用的端口是9300,而並不是9200,緣由是9200是RESTful端口,9300是API端口。

ElasticSearch之ElasticsearchTemplate

3.編寫測試

@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(indexName = "demo", type = "person", createIndex = false)
public class Person {
    /**
     * 1.索引庫(indices)         indices是index的複數,表明許多的索引,
     * 2.類型(type)             類型是模擬mysql中的table概念,一個索引庫下能夠有不一樣類型的索引,好比商品索引,訂單索引,其數據格式不一樣。不過這會致使索引庫混亂,所以將來版本中會移除這個概念
     * 3.文檔(document)         存入索引庫原始的數據。好比每一條商品信息,就是一個文檔
     * 4.字段(field)             文檔中的屬性
     * 5.映射配置(mappings)     字段的數據類型、屬性、是否索引、是否存儲等特性
     */

    /**
     * @Document 做用在類,標記實體類爲文檔對象,通常有兩個屬性
     *      1.indexName:對應索引庫名稱
     *      2.type:對應在索引庫中的類型
     *      3.shards:分片數量,默認5
     *      4.replicas:副本數量,默認1
     * @Id 做用在成員變量,標記一個字段做爲id主鍵
     * @Field 做用在成員變量,標記爲文檔的字段,並指定字段映射屬性:
     *      1.type:字段類型,是枚舉:FieldType,能夠是text、long、short、date、integer、object等
     *      2.text:存儲數據時候,會自動分詞,並生成索引
     *      3.keyword:存儲數據時候,不會分詞創建索引
     *      4.Numerical:數值類型,分兩類
     *          基本數據類型:long、interger、short、byte、double、float、half_float
     *          浮點數的高精度類型:scaled_float
     *          須要指定一個精度因子,好比10或100。elasticsearch會把真實值乘以這個因子後存儲,取出時再還原。
     *      5.Date:日期類型
     *          elasticsearch能夠對日期格式化爲字符串存儲,可是建議咱們存儲爲毫秒值,存儲爲long,節省空間。
     *      6.index:是否索引,布爾類型,默認是true
     *      7.store:是否存儲,布爾類型,默認是false
     *      8.analyzer:分詞器名稱,這裏的ik_max_word即便用ik分詞器
     */
    @Id
    private Long id;

    @Field(store = true)
    private String name;

    @Field
    private Integer age;

    @Field
    private String mail;

    @Field(store = true)
    private String hobby;
}

1)新增數據

/**
 * Spring Data ElasticSearch
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestSpringBootES {

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    /**
     * 添加數據
     */
    @Test
    public void save() {
        User user = new User();
        user.setId(1001L);
        user.setName("趙柳");
        user.setAge(20);
        user.setHobby("足球、籃球、聽音樂");

        IndexQuery indexQuery = new IndexQueryBuilder()
                .withObject(user).build();

        String index = this.elasticsearchTemplate.index(indexQuery);

        System.out.println(index);
    }
}

1.jpg

2)批量插入

@Test
public void testBulk() {
    List list = new ArrayList<>();
    for (int i = 0; i < 5000; i++) {
        User person = new User();
        person.setId(1001L + i);
        person.setAge(i % 50 + 10);
        person.setName("張三" + i);
        person.setHobby("足球、籃球、聽音樂");

        IndexQuery indexQuery = new IndexQueryBuilder().withObject(person).build();
        list.add(indexQuery);
    }
    Long start = System.currentTimeMillis();
    this.elasticsearchTemplate.bulkIndex(list);

    System.out.println("用時:" + (System.currentTimeMillis() - start));
}

1.jpg

3)局部更新,所有更新使用index覆蓋便可

@Test
public void testUpdate() {
    IndexRequest indexRequest = new IndexRequest();
    indexRequest.source("age", "30");

    UpdateQuery updateQuery = new UpdateQueryBuilder()
            .withId("1002")
            .withClass(User.class)
            .withIndexRequest(indexRequest).build();

    UpdateResponse response = this.elasticsearchTemplate.update(updateQuery);

    System.out.println(response);

}

4)刪除

@Test
public void testDelete() {
    String result = this.elasticsearchTemplate.delete(User.class, "1002");
    System.out.println(result);
}

5)查詢

@Test
public void testSearch() {
    PageRequest pageRequest = PageRequest.of(0, 10);//設置分頁參數

    SearchQuery searchQuery = new NativeSearchQueryBuilder()
            .withQuery(QueryBuilders.matchQuery("name", "趙柳"))//match查詢
            .withPageable(pageRequest)
            .build();

    AggregatedPage<User> persons = this.elasticsearchTemplate.queryForPage(searchQuery, User.class);
    System.out.println("persons ->" + persons);
    System.out.println("總頁數:" + persons.getTotalPages()); //獲取總頁數

    List<User> content = persons.getContent();// 獲取搜索到的數據
    for (User p : content) {
        System.out.println(p);
    }
}

1.jpg

ElasticSearch之ElasticsearchRepository

3.編寫測試
1)建立實體Pojo

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;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(indexName = "commodity", type = "docs", shards = 1, replicas = 0)
public class Commodity {
    @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; // 圖片地址
}

2)繼承ElasticsearchRepository

import com.example.elasticsearch.pojo.Commodity;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

import java.util.List;

public interface CommodityRepository extends ElasticsearchRepository<Commodity, Long> {

}

3)測試

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

    @Resource
    private CommodityRepository commodityRepository;

    /**
     * 建立索引
     */
    @Test
    public void createIndex() {
        boolean index = elasticsearchTemplate.createIndex(Commodity.class);
        System.out.println(index);
    }
    
    /**
     * 添加數據
     */
    @Test
    public void testInsert() {
        Commodity commodity = new Commodity(1L, "小米手機7", " 手機",
                "小米", 3499.00, "http://image.baidu.com/13123.jpg");
        Commodity save = commodityRepository.save(commodity);
        System.out.println(save);
    }

}

1.jpg

相關文章
相關標籤/搜索