基于RestHighLevelClient的Elasticsearch的基本使用

基于RestHighLevelClient的Elasticsearch的基本使用

小龙 631 2020-03-06

Elasticsearchjava客户端有两种选择
1、使用springData封装,但是跟新跟不上官方版本,我这里使用的ElasticSearch是7.6.0,SpringDataElasticSearch现在还不能支持7.6.0
2、使用官方推荐的elasticsearch-rest-high-level-client,该组件是由官方提供,提供有最新版本的
本次研究使用SpringBoot结合“elasticsearch-rest-high-level-client”,导入Maven依赖

        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>7.6.1</version>
            <exclusions>
                <exclusion>
                    <groupId>org.elasticsearch</groupId>
                    <artifactId>elasticsearch</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.elasticsearch.client</groupId>
                    <artifactId>elasticsearch-rest-client</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-client</artifactId>
            <version>7.6.1</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>7.6.1</version>
        </dependency>

配置application.yml,如果ElasticSearch没开启安全认证就无须设置username和password

elasticsearch:
  address: 192.168.5.166:9200
  username: elastic
  password: 123456

创建ESConfig类,

package cn.rsthe.es.config;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ESConfig {
    private static final int ADDRESS_LENGTH = 2;
    private static final String HTTP_SCHEME = "http";
    /** 权限验证 */
    final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
    /** 使用冒号隔开ip和端口 */
    @Value("${elasticsearch.address}")
    private String address;
    @Value("${elasticsearch.username}")
    private String username;
    @Value("${elasticsearch.password}")
    private String password;
    @Bean
    public RestClientBuilder restClientBuilder() {
        HttpHost hosts = makeHttpHost(address);
        log.debug("hosts:{}", hosts);
        //配置权限验证
        credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));
        RestClientBuilder restClientBuilder = RestClient.builder(hosts).setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
            @Override
            public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
                return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
            }
        });
        return restClientBuilder;
    }
    @Bean(name = "highLevelClient",destroyMethod = "close")
    public RestHighLevelClient highLevelClient(@Autowired RestClientBuilder restClientBuilder) {
        return new RestHighLevelClient(restClientBuilder);
    }
    /**
     * 处理请求地址
     * @param s
     * @return HttpHost
     */
    private HttpHost makeHttpHost(String s) {
        String[] address = s.split(":");
        if (address.length == ADDRESS_LENGTH) {
            String ip = address[0];
            int port = Integer.parseInt(address[1]);
            return new HttpHost(ip, port, HTTP_SCHEME);
        } else {
            return null;
        }
    }
}

1、创建索引,创建索引的方式有三种

  • 以类似Map的形式创建
@Test
    public void testAdd(){
        // 设置创建的索引名称
        CreateIndexRequest request = new CreateIndexRequest("testindex");
        //封装属性 类似于json格式
        Map<String, Object> jsonMap = new HashMap<>();
        Map<String, Object> properties = new HashMap<>();
        Map<String, Object> content = new HashMap<>();
        content.put("type", "integer");
        Map<String, Object>account = new HashMap<>();
        content .put("type", "text");
        content .put("analyzer", "ik_max_word");
        properties.put("id", content);
        properties.put("account", account);
        jsonMap.put("properties", properties);
        request.settings(Settings.builder()
                .put("index.number_of_shards", 3)
                .put("index.number_of_replicas", 2)
        );
        try {
            CreateIndexResponse createIndexResponse = highLevelClient.indices().create(request, RequestOptions.DEFAULT);
            System.err.println(createIndexResponse);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  • 第二种使用Builder的方式
  @Test
    public void testAdd() throws Exception{
        // 设置创建的索引名称
        CreateIndexRequest request = new CreateIndexRequest("testindex1-1");
        XContentBuilder builder = XContentFactory.jsonBuilder();
        builder.startObject();
        {
            builder.startObject("properties");
            {
                builder.startObject("message");
                {
                    builder.field("type", "text");
                }
                builder.endObject();
            }
            builder.endObject();
        }
        builder.endObject();
        request.mapping(builder);
        try {
            CreateIndexResponse createIndexResponse = highLevelClient.indices().create(request, RequestOptions.DEFAULT);
            System.err.println(createIndexResponse);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  • 第三种以json的方式
@Test
    public void testAdd() throws Exception{
        // 设置创建的索引名称
        CreateIndexRequest request = new CreateIndexRequest("testindex2");
        request.mapping(
                "{\n" +
                        "  \"properties\": {\n" +
                        "    \"message\": {\n" +
                        "      \"type\": \"text\"\n" +
                        "    }\n" +
                        "  }\n" +
                        "}",
                XContentType.JSON);
        try {
            CreateIndexResponse createIndexResponse = highLevelClient.indices().create(request, RequestOptions.DEFAULT);
            System.err.println(createIndexResponse);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

数据操作

需要注意的是,从ElasticSearch5.x开始就提出了弱化索引类型_type的使用,期初,我们说“索引”和关系型数据库的“库”是相似的,“类型”和“表”示对等的。这是一个不正确的对比,导致了不正确的假设。在关系型数据库中,“表”是相互独立的,一个“表”里面列和另一个“表”里的同名列是没有关系的,互不影响的。但是在类型里字段不是这样的,比如:两个不同type下的两个user_name,在ES同一个索引下,其实它们会被认为是同一个filed,你必须在两个不同的type中定义相同的 filed映射,否则,不同type中的相同字段名称就会在处理中国出现冲突,导致Lucene处理效率的下降。所有在ElasticSearch7.x就完全出去type,每个索引都默认只有_doc.

  • 新增数据,可以直接使用Vo类进行数据设置
@Test
    public void testPut() throws Exception{
        Goods goods = new Goods();
        goods.setGid(23L);
        goods.setDelflag(1);
        goods.setLastin(new Date());
        goods.setName("Hello");
        goods.setNote("你好");
        goods.setPhoto("nothing");
        goods.setPrice(19999.9);
        goods.setRecorder("nothing");
        goods.setStid(1L);
        goods.setStornum(1);
        goods.setWeight(15.0);
        goods.setWid(1L);
        goods.setWiid(1L);
        IndexRequest request = new IndexRequest("drp");
        request.id(goods.getGid().toString());
        request.source(JSON.toJSONString(goods),XContentType.JSON);
        highLevelClient.index(request,RequestOptions.DEFAULT);
    }
  • 查询数据
    @Test
    public void testGet() throws Exception{

        GetRequest request = new GetRequest("drp","23");
        GetResponse documentFields = highLevelClient.get(request, RequestOptions.DEFAULT);
        if (documentFields.isExists()){
            String sourceAsString = documentFields.getSourceAsString();
            Goods goods = JSON.parseObject(sourceAsString, Goods.class);
            System.err.println(goods);
        }
    }
  • 更新数据
 @Test
    public void testUpdate() throws Exception{
        Goods goods = new Goods();
        goods.setGid(23L);
        goods.setDelflag(1);
        goods.setLastin(new Date());
        goods.setName("Hello");
        goods.setNote("你好ya ,周末");
        goods.setPhoto("nothing");
        goods.setPrice(19999.9);
        goods.setRecorder("nothing");
        goods.setStid(1L);
        goods.setStornum(1);
        goods.setWeight(15.0);
        goods.setWid(1L);
        goods.setWiid(1L);
        UpdateRequest request = new UpdateRequest("drp",goods.getGid().toString());
        request.doc(JSON.toJSONString(goods),XContentType.JSON);
        UpdateResponse update = highLevelClient.update(request, RequestOptions.DEFAULT);
        System.err.println(update);

    }	
  • 删除数据
@Test
    public void testDelete() throws IOException {
        DeleteRequest request = new DeleteRequest("drp","23");
        DeleteResponse delete = highLevelClient.delete(request, RequestOptions.DEFAULT);
        System.err.println(delete.status());
    }
  • 基本分页查询
    @SneakyThrows
    @Test
    public void listPage() {
        int pagesize = 1;  // 页数
        int linesize = 20; // 每页显示条数
        String content = "三地方大";// 模糊查询
        // 创建索引请求,可以传入操作索引,也可以后面在设置
        SearchRequest request = new SearchRequest("drp");
        // 创建索引构建者
        SearchSourceBuilder builder = new SearchSourceBuilder();
        // 构建搜索属性
        builder.from((pagesize - 1) * linesize);  // 从第几开始
        builder.size(linesize);  //返回条数
        builder.sort(new FieldSortBuilder("price").order(SortOrder.ASC));  //对字段宁进行排序
        if (!StringUtils.isEmpty(content)){
            BoolQueryBuilder boolQueryBuilder  = QueryBuilders.boolQuery();
            // 完全匹配字段内容,“name”:字段,后面的参数是匹配内容
            TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("wiid","5");
            // 完全匹配字段内容,“name”:字段,后面的参数是匹配内容,可以设置匹配多个
            TermsQueryBuilder  termsQueryBuilder = QueryBuilders.termsQuery("note","三地","耐");
             //单个匹配, field不支持通配符, 前缀具高级特性
             MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("note",content).fuzziness(Fuzziness.AUTO);
            // 匹配全部
            MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
            boolQueryBuilder.must(matchAllQueryBuilder);
            builder.query(boolQueryBuilder);
        }
        // 传入构建进行搜索
        request.source(builder);
        SearchResponse search = highLevelClient.search(request, RequestOptions.DEFAULT);
        // 处理结果
        System.err.println(search.status());
        List<Goods> list = new ArrayList<>();
        // 获取返回数据
        SearchHits hits = search.getHits();
        hits.forEach(item -> list.add(JSON.parseObject(item.getSourceAsString(),Goods.class)));
        System.err.println(list);
    }