基于Docker安装ElasticSearch及基本使用

ElasticSearch 主要用于大数据量的检索,相比于传统的MySQL、Oracle等结构性数据库,具有较快的响应速度,丰富的查询种类,健全的响应设置,自定义权重等诸多优点

安装ES

参考文档 https://www.elastic.co/guide/en/elasticsearch/reference/7.16/docker.html ,注意,如果遇到容器启动一段时间后闪退这种情况,可能是由于服务器的内存较小或分配给docker容器的内存较小,可以通过 ES_JAVA_OPTS 参数来设置ES容器的最大内存,下面通过ES_JAVA_OPTS="-Xms256m -Xmx256m" 限制ES容器的启动内存和最大内存都为256M。

docker network create elastic

docker run -itd --name some-elasticsearch --net elastic -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms256m -Xmx256m" --name some-elasticsearch elasticsearch:7.16.1

访问http://ip:9200 可以获取版本相关的描述信息说明ES容器正常启动了。

安装Kibana

Kibana是官方提供的对ES的可视化分析界面。

docker run -d --name some-kibana --net elastic -p 5601:5601 -e "ELASTICSEARCH_HOSTS=http://some-elasticsearch:9200" kibana:7.16.1

访问http://ip:5601 可以正常进入Kibana,说明kibana容器启动成功。

点击Kibana操作界面中的 Management -> DevTools 进入控制台,进行后续的API测试。

安装Elasticsearch-head

Elasticsearch-head 提供了对ES的可视化操作界面

docker run -d -p 9100:9100 --name some-es-head mobz/elasticsearch-head:5

访问 http://ip:9100 可以正常进入,说明Elasticsearch-head容器启动成功,若访问后提示集群健康值:未连接,可以进入容器,找到对应的elasticsearch.yml文件,添加下面两行配置:

http.cors.enabled: true
http.cors.allow-origin: "*"

ElasticSearch 常用REST API

Elasticsearch提供了restful风格的接口,在对ES中的数据进行CRUD时,也可以通过postman、curl这样的接口工具进行调试

获取ES首页的基本信息

GET /

获取索引列表

GET _cat/indices

删除索引,删除名称为blogs的索引

DELETE /blogs

基本查询,查看文档列表,获取文档第一条开始的前20条数据

GET /blogs/_search
{
  "query": {
    "match_all": {}
  },
  "size": 20,
  "from": 0
}

新增文档,文档对应的索引不存在时会自动创建,文档ID不指定会自动生成,这里也可以用PUT方法

# POST /索引名称/_doc/文档ID(不指定时系统自动创建)
POST /blogs/_doc/1
{
	"content": "更新字段、更新数据",
  "title": "新增测试"
}

修改文档,和新增文档操作类似,只需要带上文档ID,就可以修改文档的字段和内容

# POST /索引名称/_doc/文档ID
# 我们可以把上面新增时候的content字段去掉,并修改title的值
POST /blogs/_doc/1
{
  "title": "修改测试"
}

根据文档ID进行搜索,在blogs索引中查询ID为1的文档

GET /blogs/_doc/1

删除文档,删除ID为1的文档

DELETE /blogs/_doc/1

文档查询,返回的数据只包含特定字段,查询blogs索引中的文档数据,并返回文档中对应的 title

GET /blogs/_search
{
  "query": {
    "match_all": {}
  },
  "_source": ["title"]
}

文档查询,根据文档中的字段进行搜索,并返回高亮的数据,默认被高亮的词是通过 em 标签括起来的,Elasticsearch可以支持自定义高亮的标签,比如下面通过 h1 来定义整个返回字段的高亮情况。

GET /blogs/_search
{
  "query": {
    "match": {
      "title": "新增"
    }
  },
  "highlight": {
    "fields": {
      "title": {}
    },
    "pre_tags": ["<h1>"],
    "post_tags": ["</h1>"]
  }
}

Java Client

ES支持Java、Go、PHP等,客户端列表查看https://www.elastic.co/guide/en/elasticsearch/client/index.html ,本文使用的es客户端版本为7.12.1参考文档 https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/7.12/index.html

在pom.xml中新增ES和json的相关依赖

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

通过以下单元测试可以对elasticsearch中的索引、文档进行CURD的操作,也可以通过远程调用的方法来实现对Elasticsearch的操作。

import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.RequestLine;
import org.apache.http.util.EntityUtils;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.*;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.junit.Test;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

public class ElasticSearch {
    /**
     * 无参请求,针对不同请求修改 Request中的请求方法、endpoint
     * 可根据文档的ID进行搜索、支持文档删除
     * @throws IOException
     */
    @Test
    public void requestNoArgs() throws IOException {
        RestHighLevelClient highLevelClient = new RestHighLevelClient(
                RestClient.builder(new HttpHost("localhost", 9200, "http"))
        );
        Request request = new Request("GET", "_cat/indices"); // 获取索引列表
        Response response = highLevelClient.getLowLevelClient().performRequest(request);
        System.out.println("==================================");
        System.out.println(EntityUtils.toString(response.getEntity()));
        System.out.println("==================================");
        highLevelClient.close();
    }

    /**
     * 文档新增、修改
     * @throws IOException
     */
    @Test
    public void docAddOrUpdate() throws IOException {
        RestHighLevelClient highLevelClient = new RestHighLevelClient(
                RestClient.builder(new HttpHost("localhost", 9200, "http"))
        );
        IndexRequest request = new IndexRequest("blogs", "_doc", "2"); // 指定ID新增文档
        Map<String, Object> map = new HashMap<>();
        map.put("title", "title-新增-修改");
        request.source(map);
        IndexResponse response = highLevelClient.index(request, RequestOptions.DEFAULT);
        System.out.println("==================================");
        System.out.println(response.toString());
        System.out.println("==================================");
        highLevelClient.close();
    }

    /**
     * 文档修改、不支持文档新增
     * @throws IOException
     */
    @Test
    public void docUpdate() throws IOException {
        RestHighLevelClient highLevelClient = new RestHighLevelClient(
                RestClient.builder(new HttpHost("localhost", 9200, "http"))
        );
        UpdateRequest request = new UpdateRequest("blogs", "1");
        Map<String, Object> map = new HashMap<>();
        map.put("title", "title");
        request.doc(map);
        UpdateResponse response = highLevelClient.update(request, RequestOptions.DEFAULT);
        System.out.println("==================================");
        System.out.println(response.toString());
        System.out.println("==================================");
        highLevelClient.close();
    }

    /**
     * 文档查询,指定查询条件
     * @throws IOException
     */
    @Test
    public void docQuery() throws IOException {
        RestHighLevelClient highLevelClient = new RestHighLevelClient(
                RestClient.builder(new HttpHost("localhost", 9200, "http"))
        );
        // 在sourceBuilder中可以构造高亮、分页等查询条件
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.size(3);
        // searchRequest()
        SearchRequest request = new SearchRequest("blogs");
        request.source(sourceBuilder);
        // search()
        SearchResponse response = highLevelClient.search(request, RequestOptions.DEFAULT);
        System.out.println("==================================");
        System.out.println(response.toString());
        System.out.println("==================================");
        highLevelClient.close();
    }
}

SpringBoot 整合Elasticsearch

springboot启动器中对Elasticsearch进行了封装可以快速使用,核心参考文档:https://docs.spring.io/spring-data/elasticsearch/docs/4.2.5/reference/html 参考文档 2:https://docs.spring.io/spring-boot/docs/2.5.5/reference/htmlsingle/#features.nosql.elasticsearch

在pom.xml中导入相关的maven依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>

在application.properties 中配置es的服务地址、账号、密码

spring.elasticsearch.rest.uris=localhost:9200

创建索引的映射对象,这里考虑续用上述的blogs

import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;

@Document(indexName = "blogs")
public class Blogs {
    @Id
    private Integer id;
    private String title;
    private String content;

    @Override
    public String toString() {
        return "Blogs{" +
                "id=" + id +
                ", title='" + title + '\'' +
                ", content='" + content + '\'' +
                '}';
    }

  	// 记得添加相应的get set 方法
}

创建测试类,测试索引、文档的相关操作

import cn.getcharzp.pojo.Blogs;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.client.reactive.DefaultReactiveElasticsearchClient;
import org.springframework.data.elasticsearch.core.*;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.data.elasticsearch.core.query.UpdateQuery;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.test.context.junit4.SpringRunner;

import java.beans.Statement;
import java.util.AbstractQueue;

@SpringBootTest
@RunWith(SpringRunner.class)
public class SpringbootElasticSearch {
    @Autowired
    private ElasticsearchRestTemplate template;

    /**
     * 根据文档ID获取文档详情
     */
    @Test
    public void getDocById() {
        Blogs blogs = template.get("1", Blogs.class);
        System.out.println(blogs);
    }

    /**
     * 使用indexOps对指定索引进行创建、判断其是否存在
     */
    @Test
    public void theIndexOps() {
        System.out.println(template.indexOps(Blogs.class).exists()); // 判断索引是否存在
        System.out.println(template.indexOps(Blogs.class).create()); // 创建索引,如果索引存在会抛出异常
    }

    /**
     * 使用search查询文档列表
     * 通过 NativeSearchQueryBuilder 来指定查询的条件
     *      通过 withQuery 来指定查询的条件
     *      通过 withHighlightBuilder 来指定文档的高亮
     *      通过 withPageable 来指定查询的页数
     */
    @Test
    public void searchDocs() {
        Query query = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.matchQuery("title", "xx"))
                .withHighlightBuilder(new HighlightBuilder().field("title"))
                .withPageable(PageRequest.of(0, 10))
                .build();
        SearchHits<Blogs> blogs = template.search(query, Blogs.class);
        for (SearchHit<Blogs> blog : blogs) {
            System.out.println(blog);
        }
    }

    /**
     * 通过 save 对文档进行保存和修改
     * 指定了ID后就可以对文档进行修改
     */
    @Test
    public void saveDoc() {
        template.save(new Blogs("iGRi030BotkAozMpjg80", "title 3 x修改", "content 3 修改"));
    }

    /**
     * 使用 delete 删除文档
     */
    @Test
    public void deleteDoc() {
        System.out.println(template.delete("1", Blogs.class));
    }
}

同时,还支持类似于JPA的方式对文档进行CRUD的操作,只需要继承ElasticsearchRepository<Blogs, String>这个接口,详细资料参考文档:https://docs.spring.io/spring-data/elasticsearch/docs/4.2.5/reference/html/#elasticsearch.repositories

posted @ 2021-12-20 08:47  GetcharZp  阅读(226)  评论(0编辑  收藏  举报