Springboot整合elasticSearch的官方API实例

前言:在上一篇博客中,我介绍了从零开始安装ElasticSearch,es是能够理解为一个操做数据的中间件,能够把它做为数据的存储仓库来对待,它具有强大的吞吐能力和计算能力,其基于Lucene服务器开发,在搜索领域具备统治般的地位。平时能够经过命令来执行语句来查询ES,可是在实际的开发中,仍是以使用API居多,关于ES的第三方框架有不少,好比BBOSS、spring也对其进行封装叫作spring-elasticsearch-data,本篇博客,咱们就来聚焦Spring的官方API,来作一个基本的demo实现api来操做Es(elasticsearch的简称)html

本篇博客的目录java

一:ElasticSearch的基本概念node

二:ElasticSearch5.2.2的安装mysql

三:ElasticSearch的官方API与Demo实现spring

四:总结sql

一:ElasticSearch的基本概念docker

1.1:索引 index数据库

 索引是ES存储数据的基本顶层单元目录.它比如就是关系型数据库中的数据库,是存储数据的地方。当搜索数据的时候,会直接从索引中查取,注意这里要与关系型数据的中的索引区分,他们是彻底不一样的概念。index的名字必须是小写,不能包含逗号、下划线或者大写字母json

1.2:类型 typebootstrap

type表示一类或者一种事物的抽象,在关系型数据库中咱们常常将一类结构类似的数据放在一个表里,而在elasticsearch中,使用相同类型的type表示相同的一类事物,它至关于关系型数据库中的表(table),用于描述文档中的各个字段的定义。每一个type都有本身的映射(mapping)或者结构定义。type的名字能够是大写或者小写,不能包含下划线或者逗号。

1.3:文档 document

document是index中的单条数据序列化成的json格式的数据,它以惟一id(_id)存储在ES中,至关于关系表的数据行,存储数据的载体,包含一个或多个存有数据的字段;

·字段(Field):文档的一个Key/Value对;

·词(Term):表示文本中的一个单词;

·标记(Token):表示在字段中出现的词,由该词的文本、偏移量(开始和结束)以及类型组成

1.4:Node 与 Cluster

Elastic 本质上是一个分布式数据库,容许多台服务器协同工做,每台服务器能够运行多个 Elastic 实例。单个 Elastic 实例称为一个节点(node)。一组节点构成一个集群(cluster)。

1.5:与mysql进行比较

 二:ElasticSearch5.2.2的安装

   上一篇博客已经介绍了ES2.0版本的安装,这篇就再也不赘述了。不过我仍是决定说一些在安装过程当中的坑,安装ES的坑确实不少,楼主分别安装了2.0版本,5.5.2版本,5.2.2版本,还用docker安装了,可是由于docker玩的不够熟练,在配置文件上更改仍是出了不少问题,最终仍是靠传统的安装方式解决的。接下来就说说ES安装过程当中的一些坑以及主要的点:

2.1:cannot allocate memory

这个是由于ES没法获取到足够的内存,解决办法就是,修改elasticseach的config目录下的jvm.options,ES默认的大小是1G,最好修改为2的整数倍的容量,具体依本身的内存而定,我修改的是256m

2.2:Exception in thread "main" java.lang.RuntimeException: don't run elasticsearch as root.   

没法以root用户启动,ES直接以root用户是没法启动的,解决办法很简单,就是创建一个ES的专用的组和用户:

groupadd elasticsearchgroup
useradd elasticsearchgroup -g elasticsearch -p elasticsearch
chown -R elasticsearchgroup:elasticsearch elasticsearch-5.2.2

这里是先创建了一个elasticsearch的组,而后再添加elasticsearch这个用户,密码也是elasticsearch,再给ES的安装目录添加权限

2.3:ERROR: bootstrap checks failed max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

解决办法就是修改系统的修改配置sysctl.conf最大文件交换数量:

vi.sysctl.conf
vm.max_map_count=655360
sysctl -p

2.4: org.elasticsearch.client.transport.NoNodeAvailableException

这个错误,是后台在链接APi出现的错误,为了解决这个问题,我花了好久(下面会说到版本号的问题),还有须要更改一下配置:

首先是编辑config目录下的 elasticsearch.yml文件:

这里的host要把#号打开,而后写上本身的外网IP的地址,还有cluster.name的名字也要记住,它在配置ES中须要用到

三:ElasticSearch的官方API与Demo实现

 3.1.1:引入TransPort5.2.2 

这里必须注意引入5.2.2版本,由于我服务上安装的ES就是5.2.2版本。ES官方API众多,每一个版本之间不是互相兼容的,若是引入的版本对应,会报一个错误:

org.elasticsearch.client.transport.NoNodeAvailableException: None of the configured nodes are available.(这个错误折磨了我好久,因此必定要以本身的服务器上的版本为准,引入netty和elasticsearch、transport的版本互相对应)

        <dependency>
            <groupId>org.elasticsearch.plugin</groupId>
            <artifactId>transport-netty4-client</artifactId>
            <version>5.2.2</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>5.2.2</version>
        </dependency>

        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>transport</artifactId>
            <version>5.2.2</version>
        </dependency>

3.1.2:springboot配置ES

新建一个类叫作ESconfig,主要是配置ES服务器的IP和端口(注意这里是9300而不是9200),9300是ES的TCP服务端口,而后实例化客户端;

package com.wyq.elasticsearch.easticsearchtest.config;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.net.InetAddress;
import java.net.UnknownHostException;

@Configuration
public class ESConfig {

    @Bean
    public TransportClient client() throws UnknownHostException {
        // 9300是es的tcp服务端口
        final  String host = "176.122.132.220";
        InetSocketTransportAddress node = new InetSocketTransportAddress(
                InetAddress.getByName(host),
                9300);

        // 设置es节点的配置信息
        Settings settings = Settings.builder()
                .put("cluster.name", "application").build();

        // 实例化es的客户端对象
        TransportClient client = new PreBuiltTransportClient(settings);
        client.addTransportAddress(node);
        return client;
    }
}

 3.1.3:添加index

若是在ES里面添加一个index,咱们须要如下命令,解释如下就是指定数据的index和type,在里面在指定fieldname

curl -X PUT 'ip:port/index/type/id’ -d '
{
  “filedname”: “xxx”
}' 

ES提供了同等的API来供咱们使用,按照下面的例子,咱们将会添加一个index叫作animal,type叫作person的数据,并经过Springboot注入TransPortClient,而后用MVC来获取请求参数,交给ES的api去处理:XContentFactory.jsonBuilder()去拼接不一样的json字符串,用client去处理:

@RestController
public class ElasticSearchDemoController {

    @Autowired
    private TransportClient client;

    public static final String index = "product";

    public static final String type = "person";


/**
     * 添加一我的的数据
     *
     * @param name    名字
     * @param sex     性别
     * @param message 说明
     * @param job 工做
     * @param onlyMark 惟一标志
     * @return
     */
    @PostMapping("/es/add")
    public ResponseEntity add(@RequestParam("name") String name,
                              @RequestParam("sex") int sex,
                              @RequestParam("message") String message,
                              @RequestParam("job") String job,
                              @RequestParam("onlyMark") int onlyMark) {
        try {
            // 将参数build成一个json对象
            XContentBuilder content = XContentFactory.jsonBuilder()
                    .startObject()
                    .field("uniqueId", onlyMark)
                    .field("name", name)
                    .field("sex", sex)
                    .field("message", message)
                    .field("job", job)
                    .endObject();

            IndexResponse response = client.prepareIndex(index, type)
                    .setSource(content)
                    .get();

            return  ResponseEntity.getSuccess(response.getResult()+""+response.getId(), HttpStatus.OK.value());
        } catch (Exception e) {
            e.printStackTrace();
            return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR.value());
        }
    }
}

3.1.4:查询index

经过id去查询,而后经过client(TransPortClient)的prepareGet方法去查询,最后返回一个GetResponse结果真后获取它的source结果:

 /**
     * 按id查询
     *
     * @param id
     * @return
     */
    @GetMapping("/es/get")
    public ResponseEntity searchById(@RequestParam("id") String id) {
        if (id.isEmpty()) {
            return new ResponseEntity(HttpStatus.NOT_FOUND.value());
        }
        // 经过索引、类型、id向es进行查询数据
        GetResponse response = client.prepareGet(index, type, id).get();

        if (!response.isExists()) {
            return new ResponseEntity(HttpStatus.NOT_FOUND.value());
        }
        return  ResponseEntity.getSuccess(response.getSource(), HttpStatus.OK.value());
    }

3.1.5:删除index

一样删除index,也是经过id来匹配的,id是惟一标志,而后交给TransPort的prepareDelete方法去删除

 /**
     * 按id删除数据
     *
     * @param id
     * @return
     */
    @GetMapping("/es/delete")
    public ResponseEntity delete(@RequestParam("id") String id) {
        DeleteResponse response = client.prepareDelete(index, type, id).get();
      return  ResponseEntity.getSuccess(response.getResult(), HttpStatus.OK.value());
    }

3.1.6:更新index

经过获取更新的内容,而后交给TransPort的update方法去更新须要更新的字段,最终返回更新的内容:

 /**
     * 根据文档id更新某个文档的数据
     *
     * @param uniqueId
     * @param name
     * @param sex
     * @param message
     * @param job
     * @return
     */
    @PutMapping("/es/update")
    public ResponseEntity update(@RequestParam("id") String id,
                                 @RequestParam(value = "name", required = false) String name,
                                 @RequestParam(value = "sex", required = false) Integer sex,
                                 @RequestParam(value = "message", required = false) String message,
                                 @RequestParam(value = "job", required = false) String job,
                                 @RequestParam(value = "uniqueId", required = false) Integer uniqueId){
        UpdateRequest update = new UpdateRequest(index, type, id);
        try {
            XContentBuilder builder = XContentFactory.jsonBuilder()
                    .startObject();

            if (Objects.nonNull(name)) {
                builder.field("name", name);
            }
            if (Objects.nonNull(sex)) {
                builder.field("sex", sex);
            }
            if (Objects.nonNull(message)) {
                builder.field("message", message);
            }
            if (Objects.nonNull(job)) {
                builder.field("job", job);
            }
            if (Objects.nonNull(uniqueId)){
                builder.field("uniqueId",uniqueId);
            }

            builder.endObject();
            update.doc(builder);
            UpdateResponse response = client.update(update).get();
            return  ResponseEntity.getSuccess(response.getResult(), HttpStatus.OK.value());
        } catch (Exception e) {
            e.printStackTrace();
            return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR.value());
        }
    }

 3.2:测试

3.2.1:打开postman,而后咱们来先来添加一个index,添加一些属性,后台提示成功:咱们在去ES中查询一下:

3.2.2:在服务器中打开,而后输入查询全部index的命令,查询animal这个index对应的数据,能够看到咱们的数据已经顺利添加:

3.2.3:查询index

上面的方式是经过命令的方式来查询的,咱们再来经过程序来测试查询index,能够看到数据查询到了:

3.2.4:更新index

后台经过传入的字段对指定有值的数据进行更新,在这里咱们更新message:

 

 3.2.5:为了验证咱们的更改是否生效,咱们再查询一下这个index,发现message已经变化了:

3.2.6:删除index

 

 3.2.7:一样咱们在验证一下是否删除成功,能够看出total为0,也表明没有数据了:

 

四:总结

    碍于篇幅,本片博文就介绍到这里,主要是讲述了ElasticSearch的官方API的使用,以及搭建ES中的一些坑,为了解决这些坑,我在下班之余耗费了好几个星期研究这些问题,ES的版本众多,必定要注意版本的选择。本篇博文适合入门级别,没有介绍ES的高级特性,关于它自己具备不少高端特性,实乃搜索利器,咱们不能把它做为数据库来看待,实际上它自己能够理解为一个搜索引擎,有着丰富的使用场景,"它远大于数据库,存储只是它的一个细小的功能",好了,但愿本篇博客能够帮助到你。

本篇博客的代码分享:连接:https://pan.baidu.com/s/1k-E15_EtHArG3iYi_3wc9A  密码:0nbp

若是关于本篇博客有任何问题,请加群:618626589

参考文档:https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html

                http://www.ruanyifeng.com/blog/2017/08/elasticsearch.html

相关文章
相关标签/搜索