Categories
Uncategorized

SpringBoot integration Elasticsearch detailed steps and code examples (with source)

Ready to work

Preparing the Environment

JAVA version

java version "1.8.0_121"
Java(TM) SE Runtime Environment (build 1.8.0_121-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode)

ES version

{
  "name": "pYaFJhZ",
  "cluster_name": "my-cluster",
  "cluster_uuid": "oC28y-cNQduGItC7qq5W8w",
  "version": {
    "number": "6.8.2",
    "build_flavor": "oss",
    "build_type": "tar",
    "build_hash": "b506955",
    "build_date": "2019-07-24T15:24:41.545295Z",
    "build_snapshot": false,
    "lucene_version": "7.7.0",
    "minimum_wire_compatibility_version": "5.6.0",
    "minimum_index_compatibility_version": "5.0.0"
  },
  "tagline": "You Know, for Search"
}

SpringBoot version

2.1.7.RELEASE

Development tools using IDEA

Installation ES

Elasticsearch introduction and installation: ElasticSearch Getting Started – Basic Concepts and Installation

Start

Creating SpringBoot project

  1. Open IDEA, click on the menu
                File> New> Project …
                Playing the selected box Spring Initializr
                
                Then Next

  2. 填写项目名等,然后Next
  3. 选择依赖的jar包(一般我只选Lombok,其他的自己手动加),然后Next

  4. 最后选择项目所在路径,点击Finish

Get called. At this point, a new SpringBoot project is fresh.

POM file

Of course, dependent on the specific jar package certainly more than those selected in step 2, wherein the operation of the ES provides a jar SpringBoot spring-boot-starter-data-elasticsearch course essential.

The final pom file posted here:



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.1.7.RELEASE
         
    
    com.lifengdi
    search
    0.0.1-SNAPSHOT
    search
    elasticsearch

    
        1.8
        6.14.2
        Greenwich.RELEASE
        1.2.4
        1.2.47
        1.0.15-SNAPSHOT
    

    
        
            
                org.springframework.cloud
                spring-cloud-dependencies
                ${spring-cloud-dependencies.version}
                pom
                import
            
        
    

    
        
            org.springframework.boot
            spring-boot-starter-web
        
        
        
            org.springframework.boot
            spring-boot-starter-data-elasticsearch
        
        
            org.springframework.boot
            spring-boot-configuration-processor
            true
        
        
        
            org.projectlombok
            lombok
            true
        
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
        
            org.testng
            testng
            ${testng.version}
            test
        
        
        
            joda-time
            joda-time
        
        
        
            com.alibaba
            fastjson
            ${fastjson.version}
        
        
        
            org.springframework.cloud
            spring-cloud-starter-openfeign
        

        
            org.apache.commons
            commons-lang3
        

    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    

application.yml file

application.yml file configuration is as follows:

server:
  port: 8080
  servlet:
    context-path: /search
spring:
  application:
    name: search
  data:
    elasticsearch:
      cluster-name: my-cluster
      cluster-nodes: localhost:9300
  jackson:
    default-property-inclusion: non_null

logging:
  file: application.log
  path: .
  level:
    root: info
    com.lifengdi.store.client: DEBUG

index-entity:
  configs:
    - docCode: store
      indexName: store
      type: base
      documentPath: com.lifengdi.document.StoreDocument

spring.data.elasticsearch.cluster-name: Cluster name

spring.data.elasticsearch.cluster-nodes: node address list, a plurality of nodes in the cluster by a comma (,) separated

ES document creation and mapping

First create a JAVA object, then declare the mapping attribute field through annotations.
    Annotations provided with a spring @ Document, @ Id, @ Field, wherein @Document acting type, @ Id, @ Field effect a tag field in the member variable, @ Id id as the primary key.

package com.lifengdi.document;

import com.lifengdi.document.store.*;
import com.lifengdi.search.annotation.DefinitionQuery;
import com.lifengdi.search.enums.QueryTypeEnum;
import lombok.Data;
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;

import java.util.List;

/**
 * 门店Document
 *
 * @author 李锋镝
 * @date Create at 19:31 2019/8/22
 */
@Document(indexName = "store", type = "base")
@Data
@DefinitionQuery(key = "page", type = QueryTypeEnum.IGNORE)
@DefinitionQuery(key = "size", type = QueryTypeEnum.IGNORE)
@DefinitionQuery(key = "q", type = QueryTypeEnum.FULLTEXT)
public class StoreDocument {

    @Id
    @DefinitionQuery(type = QueryTypeEnum.IN)
    @DefinitionQuery(key = "id", type = QueryTypeEnum.IN)
    @Field(type = FieldType.Keyword)
    private String id;

    /**
     * 基础信息
     */
    @Field(type = FieldType.Object)
    private StoreBaseInfo baseInfo;

    /**
     * 标签
     */
    @Field(type = FieldType.Nested)
    @DefinitionQuery(key = "tagCode", mapped = "tags.key", type = QueryTypeEnum.IN)
    @DefinitionQuery(key = "tagValue", mapped = "tags.value", type = QueryTypeEnum.AND)
    @DefinitionQuery(key = "_tagValue", mapped = "tags.value", type = QueryTypeEnum.IN)
    private List tags;

}

Creating an index

Providing four ElasticsearchTemplate createIndex () method to create an index, and automatically generates the class information, and may be manually specify indexName Settings

@Override
public  boolean createIndex(Class clazz) {
    return createIndexIfNotCreated(clazz);
}

@Override
public boolean createIndex(String indexName) {
    Assert.notNull(indexName, "No index defined for Query");
    return client.admin().indices().create(Requests.createIndexRequest(indexName)).actionGet().isAcknowledged();
}
@Override
public boolean createIndex(String indexName, Object settings) {
    CreateIndexRequestBuilder createIndexRequestBuilder = client.admin().indices().prepareCreate(indexName);
    if (settings instanceof String) {
        createIndexRequestBuilder.setSettings(String.valueOf(settings), Requests.INDEX_CONTENT_TYPE);
    } else if (settings instanceof Map) {
        createIndexRequestBuilder.setSettings((Map) settings);
    } else if (settings instanceof XContentBuilder) {
        createIndexRequestBuilder.setSettings((XContentBuilder) settings);
    }
    return createIndexRequestBuilder.execute().actionGet().isAcknowledged();
}

@Override
public  boolean createIndex(Class clazz, Object settings) {
    return createIndex(getPersistentEntityFor(clazz).getIndexName(), settings);
}

Create a map

ElasticsearchTemplate provides three putMapping () method to create the map

@Override
public  boolean putMapping(Class clazz) {
    if (clazz.isAnnotationPresent(Mapping.class)) {
        String mappingPath = clazz.getAnnotation(Mapping.class).mappingPath();
        if (!StringUtils.isEmpty(mappingPath)) {
            String mappings = readFileFromClasspath(mappingPath);
            if (!StringUtils.isEmpty(mappings)) {
                return putMapping(clazz, mappings);
            }
        } else {
            LOGGER.info("mappingPath in @Mapping has to be defined. Building mappings using @Field");
        }
    }
    ElasticsearchPersistentEntity persistentEntity = getPersistentEntityFor(clazz);
    XContentBuilder xContentBuilder = null;
    try {

        ElasticsearchPersistentProperty property = persistentEntity.getRequiredIdProperty();

        xContentBuilder = buildMapping(clazz, persistentEntity.getIndexType(),
                property.getFieldName(), persistentEntity.getParentType());
    } catch (Exception e) {
        throw new ElasticsearchException("Failed to build mapping for " + clazz.getSimpleName(), e);
    }
    return putMapping(clazz, xContentBuilder);
}

@Override
public  boolean putMapping(Class clazz, Object mapping) {
    return putMapping(getPersistentEntityFor(clazz).getIndexName(), getPersistentEntityFor(clazz).getIndexType(),
            mapping);
}

@Override
public boolean putMapping(String indexName, String type, Object mapping) {
    Assert.notNull(indexName, "No index defined for putMapping()");
    Assert.notNull(type, "No type defined for putMapping()");
    PutMappingRequestBuilder requestBuilder = client.admin().indices().preparePutMapping(indexName).setType(type);
    if (mapping instanceof String) {
        requestBuilder.setSource(String.valueOf(mapping), XContentType.JSON);
    } else if (mapping instanceof Map) {
        requestBuilder.setSource((Map) mapping);
    } else if (mapping instanceof XContentBuilder) {
        requestBuilder.setSource((XContentBuilder) mapping);
    }
    return requestBuilder.execute().actionGet().isAcknowledged();
}

Test code as follows

@Test
public void testCreate() {
    System.out.println(elasticsearchTemplate.createIndex(StoreDocument.class));
    System.out.println(elasticsearchTemplate.putMapping(StoreDocument.class));
}

Delete Index

ElasticsearchTemplate offers two deleteIndex () method to delete the index

@Override
public  boolean deleteIndex(Class clazz) {
    return deleteIndex(getPersistentEntityFor(clazz).getIndexName());
}

@Override
public boolean deleteIndex(String indexName) {
    Assert.notNull(indexName, "No index defined for delete operation");
    if (indexExists(indexName)) {
        return client.admin().indices().delete(new DeleteIndexRequest(indexName)).actionGet().isAcknowledged();
    }
    return false;
}

New & modified documents

In Elasticsearch document is immutable and can not modify them. Conversely, if you want to update an existing document, the index needs to be rebuilt or replaced.

You can use the same interface and added to the document modify operation. The distinction is based on id.

New & document modification provides the following two methods wherein a provided by ElasticsearchTemplate index () method:

@Override
public String index(IndexQuery query) {
    String documentId = prepareIndex(query).execute().actionGet().getId();
    // We should call this because we are not going through a mapper.
    if (query.getObject() != null) {
        setPersistentEntityId(query.getObject(), documentId);
    }
    return documentId;
}

Sample code is as follows:

/**
 * 更新索引
 * @param indexName 索引名称
 * @param type 索引类型
 * @param id ID
 * @param jsonDoc JSON格式的文档
 * @param refresh 是否刷新索引
 * @return ID
 */
public String index(String indexName, String type, String id, JsonNode jsonDoc, boolean refresh)
            throws JsonProcessingException {

        log.info("AbstractDocumentIndexService更新索引.indexName:{},type:{},id:{},jsonDoc:{}", indexName, type, id, jsonDoc);
        IndexQuery indexQuery = new IndexQueryBuilder()
                .withIndexName(indexName)
                .withType(type)
                .withId(id)
                .withSource(objectMapper.writeValueAsString(jsonDoc))
                .build();
        try {
            if (elasticsearchTemplate.indexExists(indexName)) {
                String index = elasticsearchTemplate.index(indexQuery);
                if (refresh) {
                    elasticsearchTemplate.refresh(indexName);
                }
                return index;
            }
        } catch (Exception e) {
            log.error("更新索引失败,刷新ES重试", e);
            elasticsearchTemplate.refresh(indexName);
            return elasticsearchTemplate.index(indexQuery);
        }
        throw BaseException.INDEX_NOT_EXISTS_EXCEPTION.build();
    }

Another is the Repository through the interface. The ES Repository Spring provides interfaces for ElasticsearchCrudRepository, so we can direct new interface defined amount, then you can achieve ElasticsearchCrudRepository:

package com.taoche.docindex.repo;

import com.taoche.document.StoreDocument;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

/**
 * 门店Repository
 * @author 李锋镝
 * @date Create at 09:30 2019/8/23
 */
public interface StoreRepository extends ElasticsearchRepository { }

Sample code is as follows:

@Test
public void testSave() {

    StoreDocument storeDocument = new StoreDocument();
    storeDocument.setId("1");
    StoreBaseInfo baseInfo = new StoreBaseInfo();
    baseInfo.setStoreId("1");
    baseInfo.setCreatedTime(DateTime.now());
    storeDocument.setBaseInfo(baseInfo);

    storeRepository.save(storeDocument);
}

Inquire

ES main function is to query, ElasticsearchRepository also provides basic query interface, such findById (), findAll (), findAllById (), search () or the like; of course possible to use another function Spring Data provided: Spring Data JPA – create a query by the method name, of course, need to follow certain rules, such as your method name is called findByTitle (), then you know that it is based on the title query, and then automatically help you complete, here is not to say carefully.

Said above can basically meet the general queries, more complex queries can not do anything, which need to use custom queries, where you can see my another blog SpringBoot use annotations Elasticsearch way to build queries, multi-criteria complex queries, where the edge is described in detail.

There is also a more powerful functions, aggregation elasticsearch; main polymerization is achieved statistical data analysis. This temporarily not used, it depends on the aggregation of small partners may be disappointed ~ ~ ~ ~ ha ha ha

There will be another time alone to say – will be there after aggregation.

So far, SpringBoot integrate basic end Elasticsearch, what you do not understand, please leave a message ~

Source

Git project Address: search

If you think there is any help, please help thumbs up, little star point support what ~

Thank you ~ ~

Original link: https: //www.lifengdi.com/archives/article/945

Leave a Reply