SpringBoot integrates ElasticSearch to achieve multi-version compatibility

foreword

In the previous article on learning SpringBoot , Mybatis, Druid and PageHelper were integrated and the operation of multiple data sources was implemented. This article mainly introduces and uses the most popular search engine ElastiSearch , and uses it in combination with SpringBoot .

Introduction to ElasticSearch

ElasticSearch is a search server based on Lucene , in fact, it encapsulates Lucene and provides the operation interface of REST API. As a highly scalable open source full-text search and analysis engine, ElasticSearch can be used to quickly store, search and analyze big data. .
The main features of ElasticSearch : distributed, highly available, asynchronous writing, multiple APIs, and document-oriented.
ElasticSearch core concepts: near real-time, cluster, node (save data), index, sharding (sharding the index), replica (multiple replicas can be set for sharding). It can quickly store, search and analyze massive data.
ElasticSearch use cases: Wikipedia, Stack Overflow, Github, etc.

SpringBoot integrates Elasticsearch

Before using SpringBoot to integrate Elasticsearch , we should understand the relationship between the corresponding versions .

Spring Boot Version (x) Spring Data Elasticsearch Version (y) Elasticsearch Version (z)
x <= 1.3.5 y <= 1.3.4 z <= 1.7.2*
x >= 1.4.x 2.0.0 <=y < 5.0.0** 2.0.0 <= z < 5.0.0**

The version of SpringBoot we use here is 1.5.9, and the version of Elasticsearch is 2.3.5.

Using SpringBoot to integrate Elasticsearch is generally encapsulated with SpringData , and then the dao layer interface inherits the ElasticsearchRepository class, which implements many methods, such as the commonly used CRUD methods.

Use of SpringData

First of all, make relevant preparations before using it.

The Maven configuration is as follows:

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
             <version>1.5.9.RELEASE</version>
        </dependency>
  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
             <version>1.5.9.RELEASE</version>
        </dependency>

Configuration of application.properties

spring.data.elasticsearch.repositories.enabled = true
spring.data.elasticsearch.cluster-nodes =127.0.0.1\:9300

Note: 9300 is the port for the Java client. 9200 is the interface that supports Restful HTTP.

More configurations:

spring.data.elasticsearch.cluster-name Elasticsearch 集群名。(默认值: elasticsearch)
spring.data.elasticsearch.cluster-nodes 集群节点地址列表,用逗号分隔。如果没有指定,就启动一个客户端节点。
spring.data.elasticsearch.propertie 用来配置客户端的额外属性。
spring.data.elasticsearch.repositories.enabled 开启 Elasticsearch 仓库。(默认值:true。)

code writing

entity class

@Document(indexName = "userindex", type = "user")
public class User implements Serializable{
     /**
     * 
     */
    private static final long serialVersionUID = 1L;
    /** 编号 */
     private Long id;
     /** 姓名 */
     private String name;
     
     /** 年龄 */
     private Integer age;
     
     /** 描述 */  
     private String description;
     
     /** 创建时间 */
     private String createtm;

    // getter和setter 略

When using SpringData , it needs to set indexName and type in the entity class, which is equivalent to library and table if compared with traditional database . It should be noted that both indexName and type must be lowercase!!!

dao layers

public interface UserDao extends ElasticsearchRepository<User, Long>{
}

The dao layer is relatively simple here, just inherit the ElasticsearchRepository class. The main methods are save, delete and search. Among them, the save method is quite like insert and update. The delete method is mainly to delete data and index library. As for search, it is a query, including some commonly used queries, such as pagination and weight.

Service layer

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao userDao;
    @Override
    public boolean insert(User user) {
        boolean falg=false;
        try{
            userDao.save(user);
            falg=true;
        }catch(Exception e){
            e.printStackTrace();
        }
        return falg;
    }

    @Override
    public List<User> search(String searchContent) {
          QueryStringQueryBuilder builder = new QueryStringQueryBuilder(searchContent);
          System.out.println("查询的语句:"+builder);
          Iterable<User> searchResult = userDao.search(builder);
          Iterator<User> iterator = searchResult.iterator();
          List<User> list=new ArrayList<User>();
          while (iterator.hasNext()) {
            list.add(iterator.next());
          }
       return list;
    }
    
    
    
    @Override
    public List<User> searchUser(Integer pageNumber, Integer pageSize,String searchContent) {
         // 分页参数
        Pageable pageable = new PageRequest(pageNumber, pageSize);
        QueryStringQueryBuilder builder = new QueryStringQueryBuilder(searchContent);
        SearchQuery searchQuery = new NativeSearchQueryBuilder().withPageable(pageable).withQuery(builder).build();
        System.out.println("查询的语句:" + searchQuery.getQuery().toString());
        Page<User> searchPageResults = userDao.search(searchQuery);
        return searchPageResults.getContent();
    }
    

    @Override
    public List<User> searchUserByWeight(String searchContent) {
     // 根据权重进行查询
        FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery()
                .add(QueryBuilders.boolQuery().should(QueryBuilders.matchQuery("name", searchContent)),
                    ScoreFunctionBuilders.weightFactorFunction(10))
                .add(QueryBuilders.boolQuery().should(QueryBuilders.matchQuery("description", searchContent)),
                        ScoreFunctionBuilders.weightFactorFunction(100)).setMinScore(2);
        System.out.println("查询的语句:" + functionScoreQueryBuilder.toString());
        Iterable<User> searchResult = userDao.search(functionScoreQueryBuilder);
        Iterator<User> iterator = searchResult.iterator();
        List<User> list=new ArrayList<User>();
        while (iterator.hasNext()) {
            list.add(iterator.next());
        }
        return list;
    }
}

Here I simply wrote a few methods, the main method of which is query. Queries include full-text searches, paginated queries, and weighted queries. What needs to be explained is the weighted query. The higher the weighted score, the higher the query results. If no score is set for other data, their default score is 1. If you do not want to query these statements, only You need to use setMinScore to set it to greater than 1.

code test

Call the interface to add data

Added data:

POST http://localhost:8086/api/user

{"id":1,"name":"张三","age":20,"description":"张三是个Java开发工程师","createtm":"2018-4-25 11:07:42"}
{"id":2,"name":"李四","age":24,"description":"李四是个测试工程师","createtm":"1980-2-15 19:01:32"}
{"id":3,"name":"王五","age":25,"description":"王五是个运维工程师","createtm":"2016-8-21 06:11:32"}

Make a full text query
request

http://localhost:8086/api/user?searchContent=工程师

return

[{"id":2,"name":"李四","age":14,"description":"李四是个测试工程师","createtm": "1980-2-15 19:01:32"},
{"id":1,"name":"张三","age":20,"description":"张三是个Java开发工程师", "createtm": "2018-4-25 11:07:42"},
{"id":3,"name":"王五","age":25,"description":"王五是个运维工程师","createtm": "2016-8-21 06:11:32"}]

Make a paginated query
request

http://localhost:8086/api/user?pageNumber=0&pageSize=2&searchContent=工程师

return

[{"id":2,"name":"李四","age":14,"description":"李四是个测试工程师"},{"id":1,"name":"张三","age":20,"description":"张三是个Java开发工程师"}]

Make a weight query
request

http://localhost:8086/api/user2?searchContent=李四

return

[{"id":2,"name":"李四","age":24,"description":"李四是个测试工程师","createtm":"1980-2-15 19:01:32"}]

The statement printed by the weight query:

查询的语句:{{
  "function_score" : {
    "functions" : [ {
      "filter" : {
        "bool" : {
          "should" : {
            "match" : {
              "name" : {
                "query" : "李四",
                "type" : "boolean"
              }
            }
          }
        }
      },
      "weight" : 10.0
    }, {
      "filter" : {
        "bool" : {
          "should" : {
            "match" : {
              "description" : {
                "query" : "李四",
                "type" : "boolean"
              }
            }
          }
        }
      },
      "weight" : 100.0
    } ],
    "min_score" : 2.0
  }
}

Note: In the test, because the minimum weight of setMinScore is set to be divided into 2, irrelevant data will not be displayed. If you want to display it, you can remove it in the code.

After adding data, you can enter: http://localhost:9200/_plugin/head/ in the browser
and click Basic Query to view the added data. If you want to query by statement, you can paste the query statement printed on the console in the program into the query interface for query!

Note: I installed ElasticSearch on Windows and installed the ES plugin head. The specific installation steps are at the end of the article.

In addition to SpringData, there are other ways to operate ElasticSearch .
For example, using the native ElasticSearch API , using the TransportClient class to implement.
Or use Spring encapsulation, just inject Beans at the Service layer.
Example:

@Autowired
 ElasticsearchTemplate elasticsearchTemplate; 

However, the above methods all have their limitations, that is, with the version change of ElasticSearch , the related Java API is constantly being adjusted, that is, after the ElasticSearch server version is changed, the client code may need to be rewritten.
Therefore, a very useful third-party tool JestClient is introduced . It encapsulates ElasticSearch and fills the gap of the ElasticSearch HttpRest interface client. It is suitable for versions above ElasticSearch 2.x, and there is no need to change the code due to the change of the ElasticSearch server version. !

IsClient

First add the following dependencies to Maven:

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

Then write the relevant test code.
The comments in the code should be complete, so I won't go into too much detail about the code here.

import java.util.ArrayList;
import java.util.List;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import com.pancm.pojo.User;
import io.searchbox.client.JestClient;
import io.searchbox.client.JestClientFactory;
import io.searchbox.client.JestResult;
import io.searchbox.client.config.HttpClientConfig;
import io.searchbox.core.Bulk;
import io.searchbox.core.BulkResult;
import io.searchbox.core.Delete;
import io.searchbox.core.DocumentResult;
import io.searchbox.core.Index;
import io.searchbox.core.Search;
import io.searchbox.indices.CreateIndex;
import io.searchbox.indices.DeleteIndex;
import io.searchbox.indices.mapping.GetMapping;
import io.searchbox.indices.mapping.PutMapping;

public class JestTest {  
        private static JestClient jestClient;  
        private static String indexName = "userindex";  
//      private static String indexName = "userindex2";  
        private static String typeName = "user";  
        private static String elasticIps="http://192.169.2.98:9200";
//      private static String elasticIps="http://127.0.0.1:9200";
        
        
        public static void main(String[] args) throws Exception {
            jestClient = getJestClient();  
            insertBatch();
            serach1();
            serach2();
            serach3();
            jestClient.close();  
            
        }
        
        private static  JestClient getJestClient() {  
            JestClientFactory factory = new JestClientFactory();  
            factory.setHttpClientConfig(new HttpClientConfig.Builder(elasticIps).connTimeout(60000).readTimeout(60000).multiThreaded(true).build());  
            return factory.getObject();  
        }  
        
        public static void insertBatch() {
            List<Object> objs = new ArrayList<Object>();
            objs.add(new User(1L, "张三", 20, "张三是个Java开发工程师","2018-4-25 11:07:42"));
            objs.add(new User(2L, "李四", 24, "李四是个测试工程师","1980-2-15 19:01:32"));
            objs.add(new User(3L, "王五", 25, "王五是个运维工程师","2016-8-21 06:11:32"));
            boolean result = false;
            try {
                result = insertBatch(jestClient,indexName, typeName,objs);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("批量新增:"+result);
        }
        
        
        /**
         * 全文搜索
         */
        public static void serach1() {
            String query ="工程师";
            try {
                SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); 
                 searchSourceBuilder.query(QueryBuilders.queryStringQuery(query)); 
                 //分页设置
                 searchSourceBuilder.from(0).size(2); 
                System.out.println("全文搜索查询语句:"+searchSourceBuilder.toString());
                System.out.println("全文搜索返回结果:"+search(jestClient,indexName, typeName, searchSourceBuilder.toString()));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        /**
         * 精确搜索
         */
        public static void serach2() {
            try {
                SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); 
                searchSourceBuilder.query(QueryBuilders.termQuery("age", 24)); 
                System.out.println("精确搜索查询语句:"+searchSourceBuilder.toString());
                System.out.println("精确搜索返回结果:"+search(jestClient,indexName, typeName, searchSourceBuilder.toString()));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        
        /**
         * 区间搜索
         */
        public static void serach3() {
            String createtm="createtm";
            String from="2016-8-21 06:11:32";
            String to="2018-8-21 06:11:32";
            
            try {
                SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); 
                searchSourceBuilder.query(QueryBuilders.rangeQuery(createtm).gte(from).lte(to)); 
                System.out.println("区间搜索语句:"+searchSourceBuilder.toString());
                System.out.println("区间搜索返回结果:"+search(jestClient,indexName, typeName, searchSourceBuilder.toString()));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        
        /**
         * 创建索引
         * @param indexName
         * @return
         * @throws Exception
         */
        public boolean createIndex(JestClient jestClient,String indexName) throws Exception {  
            JestResult jr = jestClient.execute(new CreateIndex.Builder(indexName).build());  
            return jr.isSucceeded();  
        }  
          
        /**
         * 新增数据
         * @param indexName
         * @param typeName
         * @param source
         * @return
         * @throws Exception
         */
        public boolean insert(JestClient jestClient,String indexName, String typeName, String source) throws Exception {  
            PutMapping putMapping = new PutMapping.Builder(indexName, typeName, source).build();  
            JestResult jr = jestClient.execute(putMapping);  
            return jr.isSucceeded();  
        }  
          
        
         /**
          * 查询数据
          * @param indexName
          * @param typeName
          * @return
          * @throws Exception
          */
        public static String getIndexMapping(JestClient jestClient,String indexName, String typeName) throws Exception {  
            GetMapping getMapping = new GetMapping.Builder().addIndex(indexName).addType(typeName).build();  
            JestResult jr =jestClient.execute(getMapping);  
            return jr.getJsonString();  
         }  
          
        
        
       /**
        * 批量新增数据
        * @param indexName
        * @param typeName
        * @param objs
        * @return
        * @throws Exception
        */
        public static boolean insertBatch(JestClient jestClient,String indexName, String typeName, List<Object> objs) throws Exception {  
            Bulk.Builder bulk = new Bulk.Builder().defaultIndex(indexName).defaultType(typeName);  
            for (Object obj : objs) {  
                Index index = new Index.Builder(obj).build();  
                 bulk.addAction(index);  
            }  
            BulkResult br = jestClient.execute(bulk.build());  
            return br.isSucceeded();  
           }  
          
        /**
         * 全文搜索
         * @param indexName
         * @param typeName
         * @param query
         * @return
         * @throws Exception
         */
        public static String search(JestClient jestClient,String indexName, String typeName, String query) throws Exception {  
             Search search = new Search.Builder(query)
             .addIndex(indexName)
             .addType(typeName)  
             .build(); 
            JestResult jr = jestClient.execute(search);  
//          System.out.println("--"+jr.getJsonString());
//          System.out.println("--"+jr.getSourceAsObject(User.class));
            return jr.getSourceAsString();  
         }  
          
          
        
       
          
       /**
        * 删除索引
        * @param indexName
        * @return
        * @throws Exception
        */
        public boolean delete(JestClient jestClient,String indexName) throws Exception {  
            JestResult jr = jestClient.execute(new DeleteIndex.Builder(indexName).build());  
            return jr.isSucceeded();  
        }  
          
       /**
        * 删除数据
        * @param indexName
        * @param typeName
        * @param id
        * @return
        * @throws Exception
        */
        public boolean delete(JestClient jestClient,String indexName, String typeName, String id) throws Exception {  
            DocumentResult dr = jestClient.execute(new Delete.Builder(id).index(indexName).type(typeName).build());  
            return dr.isSucceeded();  
        }  

Note: Before testing, let me explain that the version of ElasticSearch installed on the local windows system is 2.3.5, and the version of ElasticSearch installed on the linux server is 6.2.

Test Results

research all

全文搜索查询语句:{
  "from" : 0,
  "size" : 2,
  "query" : {
    "query_string" : {
      "query" : "工程师"
    }
  }
}

全文搜索返回结果:{"id":1,"name":"张三","age":20,"description":"张三是个Java开发工程师","createtm":"2018-4-25 11:07:42"},{"id":2,"name":"李四","age":24,"description":"李四是个测试工程师","createtm":"1980-2-15 19:01:32"}

match search

精确搜索查询语句:{
  "query" : {
    "term" : {
      "age" : 24
    }
  }
}

精确搜索返回结果:{"id":2,"name":"李四","age":24,"description":"李四是个测试工程师","createtm":"1980-2-15 19:01:32"}

time interval search

区间搜索语句:{
  "query" : {
    "range" : {
      "createtm" : {
        "from" : "2016-8-21 06:11:32",
        "to" : "2018-8-21 06:11:32",
        "include_lower" : true,
        "include_upper" : true
      }
    }
  }
}
区间搜索返回结果:{"id":1,"name":"张三","age":20,"description":"张三是个Java开发工程师","createtm":"2018-4-25 11:07:42"}

After adding data, we can perform related queries in Kibana of Linux. The query results are as follows:

Note: Kibana is an open source software in ELK. Kibana can provide Logstash and ElasticSearch with a friendly web interface for log analysis, which can help summarize, analyze and search important data logs.

The results returned by the tests in the above code are what we expected. Among them, only a small part of JestClient is used. For more use, you can check the official documentation of JestClient.

Install ElasticSearch on Windows

1. File preparation
Download address:
https://www.elastic.co/downloads
Select the relevant version of ElasticSearch, then select the ZIP file with the suffix to download, and unzip it after downloading.

2. Start Elasticsearch and
enter the bin directory, run elasticsearch.bat
and then enter: localhost:9200
Successfully display the interface to indicate success!

3. Install the ES plug-in
web management interface head installation
Enter the bin directory, open cmd, enter the dos interface,
enter: plugin install mobz/elasticsearch-head
download
After successful download, enter in the browser: http://localhost:9200/_plugin/head/
If the interface is displayed , the installation is successful!

4. Register the service
Enter the bin directory, open cmd, enter the dos interface, and enter
in turn:
service.bat install
service.bat start
After successful, enter
services.msc
to jump to the Service service interface, and you can directly view the running status of es!

other

ElasticSearch official website API address:
https://www.elastic.co/guide/en/elasticsearch/client/java-api/2.3/index.html

JestClientGithub address:
https://github.com/searchbox-io/Jest

I put the project on github.
https://github.com/xuwujing/springBoot

If it feels good, I hope to give a star by the way.
This is the end of this article, thank you for reading.

Copyright statement:
Author: Nothingness
Blog Garden Source: http://www.cnblogs.com/xuwujing
CSDN Source: http://blog.csdn.net/qazwsxpcm    
Personal Blog Source: http://www.panchengming.com
Original It's not easy, please indicate the source when reprinting, thank you!

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325624935&siteId=291194637