XContentBuilder 创建es索引mappin结构

目录

1. es常用方法封装接口:

2. es常用方法封装实现类:


说明:

XContentBuilder 创建es索引mappin结构方式,在下面的java代码‘2. es常用方法封装实现类’中。

1. es常用方法封装接口:


package com.boot.base.config.es.service;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.boot.base.config.es.service.impl.ElasticSearchServiceImpl;

import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * @Description es常用方法封装接口
 * @Author admin
 * @Date 2021/5/24
 */
public interface ElasticSearchService {

    ElasticSearchServiceImpl selectIndex(String index);

    boolean createIndex(String index, String type);

    boolean existIndex(String index);

    boolean deleteIndex(String index);

    void createDocument(String id, Map<String, Object> source);

    void updateDocument(String id, Map<String, Object> source) throws IOException;

    void deleteDocument(String type, String id);

    void bulkDocument(String type, Map<String, Map<String, Object>> sources);

    void bulkDeleteDocument(String type, List<Integer> ids);

    Page<Map<String, Object>> searchDocument(Page page, String keyword, String... fields);

}

2. es常用方法封装实现类:

package com.boot.base.config.es.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.boot.base.common.exception.WorkException;
import com.boot.base.config.es.service.ElasticSearchService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnResource;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ResourceUtils;
import javax.annotation.PostConstruct;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description es常用方法封装实现类
 *
 * 配置文件结构必须满足如下要求:
 *  1.必须指定index,如:blue_whale_news_3
 *      2.必须存在的节点mappings
 *          3.必须指定type,如:news
 *              4.必须存在的节点properties
 *                  5.建议指定字段名及其类型等,如:
 *                      "content": {
 *                          "type": "text",
 *                          "fields": {
 *                              "keyword": {
 *                                  "type": "keyword",
 *                                  "ignore_above": 256
 *                               }
 *                           }
 *                    节点"fields": {...}为非必填!
 *
 * 示例(可直接拷贝该示例并名命为indices.json,最终的存放路径为:classpath:es.index/indices.json):
 * [{
 *   "blue_whale_news_3": {
 *     "mappings": {
 *       "news": {
 *         "properties": {
 *           "content": {
 *             "type": "text",
 *             "fields": {
 *               "keyword": {
 *                 "type": "keyword",
 *                 "ignore_above": 256
 *               }
 *             }
 *           },
 *           "createTime": {
 *             "type": "date"
 *           }
 *         }
 *       }
 *     }
 *   }
 * }]
 *
 *
 *
 * @Author admin
 * @Date 2021/5/24
 */
@Slf4j
@Component
@ConditionalOnResource(resources = "classpath:es.index/indices.json")
public class ElasticSearchServiceImpl implements ElasticSearchService {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    /** es索引 */
    private String index;
    /** 指定的es索引的type */
    private String type;

    /** 所有被加载的索引信息:key: {@link index}, value: {@link type} */
    private Map<String, String> loadedIndices = new HashMap<>();

    @Override
    public ElasticSearchServiceImpl selectIndex(String index) {
        this.index = index;
        this.index = loadedIndices.get(index);
        return this;
    }

    @PostConstruct
    private void createIndices() {
        List<IndexMapping> indexMappings = parseIndicesConfFile();
        doCreateIndices(indexMappings);
    }

    /**
     * 循环创建索引
     *
     * @param indexMappings
     */
    private void doCreateIndices(List<IndexMapping> indexMappings) {
        if (ObjectUtils.isEmpty(indexMappings)) {
            return;
        }
        for (IndexMapping indexMapping : indexMappings) {
            if (!this.existIndex(indexMapping.getIndex())) {
                this.doCreateIndex(indexMapping.getIndex(), indexMapping.getType(), indexMapping.getXContentBuilder());
            }
        }
    }

    /**
     * 解析索引配置文件
     *
     * @return
     * @throws FileNotFoundException
     */
    private List<IndexMapping> parseIndicesConfFile() {
        File file = null;
        try {
            file = ResourceUtils.getFile("classpath:es.index/indices.json");
        } catch (FileNotFoundException fileNotFoundException) {
            log.error("指定的es索引配置文件[classpath:es.index/indices.json]不存在,异常:", file.getAbsolutePath(), fileNotFoundException);
        }
        String jsonStr;
        List<IndexMapping> indexMappings = null;
        try {
            jsonStr = IOUtils.toString(file.toURI(), StandardCharsets.UTF_8);
            final JSONArray indices = JSON.parseArray(jsonStr);
            indexMappings = doParseIndices(indices);
        } catch (Exception e) {
            log.error("无法创建es索引,解析配置文件[{}]异常:", file.getAbsolutePath(), e);
        }
        return indexMappings;
    }

    /**
     * 解析JSONArray格式的多个索引
     *
     * @param indices
     */
    private List<IndexMapping> doParseIndices(JSONArray indices) {
        List<IndexMapping> indexMappings = new ArrayList<>();
        if (ObjectUtils.isEmpty(indices)) {
            return indexMappings;
        }
        for (Object index : indices) {
            if (index instanceof JSONObject) {
                doParseIndex((JSONObject) index, indexMappings);
            } else {
                log.error("无法解析索引{[]},只能解析json格式的内容!", index);
            }
        }
        return indexMappings;
    }

    /**
     * 解析单个json格式的索引文件
     *
     * @param idx
     * @param indexMappings
     */
    private void doParseIndex(JSONObject idx, List<IndexMapping> indexMappings) {
        if (idx.isEmpty()) {
            return;
        }
        final String indexName = idx.keySet().iterator().next();
        final Object mappingsObj = ((Map<String, Object>) idx.get(indexName)).get("mappings");
        if (mappingsObj == null) {
            return;
        }
        final Map<String, Object> mappings = (Map<String, Object>) mappingsObj;
        final String typeName = mappings.keySet().iterator().next();
        loadedIndices.put(indexName, typeName);

        // 至少有index和type才创建索引
        IndexMapping indexMapping = new IndexMapping();
        indexMapping.setIndex(indexName).setType(typeName);
        indexMappings.add(indexMapping);
        final Object propertiesObj = mappings.get(typeName);
        final Map<String, Object> properties = (Map<String, Object>) propertiesObj;
        if (propertiesObj == null || properties.isEmpty()) {
            return;
        }

        // 构造index的mappings结构
        XContentBuilder builder;
        try {
            builder = XContentFactory.jsonBuilder().map(mappings);
            indexMapping.setXContentBuilder(builder);
        } catch (IOException e) {
            log.error("创建索引失败,构造index的mappings结构异常:", e);
        }

    }

    /**
     * es的mappings结构中属性对应的实体类
     *
     */
    private class IndexMapping {
        private String index;
        private String type;
        private XContentBuilder xContentBuilder;

        public String getIndex() {
            return index;
        }

        public IndexMapping setIndex(String index) {
            this.index = index;
            return this;
        }

        public String getType() {
            return type;
        }

        public IndexMapping setType(String type) {
            this.type = type;
            return this;
        }

        public XContentBuilder getXContentBuilder() {
            return xContentBuilder;
        }

        public IndexMapping setXContentBuilder(XContentBuilder xContentBuilder) {
            this.xContentBuilder = xContentBuilder;
            return this;
        }
    }

    /**
     * 创建指定的索引
     *
     * @param index
     * @param type
     * @param xContentBuilder
     * @return
     */
    public boolean doCreateIndex(String index, String type, XContentBuilder xContentBuilder) {
        try {
            CreateIndexRequest request = new CreateIndexRequest(index);
            // request.settings(Settings.builder().put("index.number_of_shards", 1).put("index.number_of_shards", 5));
            request.mapping(type, xContentBuilder);
            return this.restHighLevelClient.indices().create(request, RequestOptions.DEFAULT).isAcknowledged();
        } catch (IOException e) {
            log.error("创建索引[index={},type={}]异常:", index, type, e);
            return false;
        }
    }

    @Override
    public boolean createIndex(String index, String type) {
        try {
            CreateIndexRequest request = new CreateIndexRequest(index);
//            request.settings(Settings.builder().put("index.number_of_shards", 1).put("index.number_of_shards", 5));
            CreateIndexResponse response = this.restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);
            return response.isAcknowledged();
        } catch (IOException e) {
            log.error("创建索引[index={},type={}]异常:", index, type, e);
            return false;
        }
    }

    @Override
    public boolean existIndex(String index) {
        GetIndexRequest request = new GetIndexRequest();
        request.indices(index).local(false).humanReadable(true);
        try {
            return restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            log.error("查询索引[index={},type={}]是否存在时异常:", index, type, e);
        }
        return false;
    }

    @Override
    public boolean deleteIndex(String index) {
        return false;
    }

    @Override
    public void createDocument(String id, Map<String, Object> source) {
        IndexRequest request = new IndexRequest(index, type, id);
        request.source(source);
        try {
            restHighLevelClient.index(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            log.error("创建es的document[index={},type={},id={},source={}]异常:", index, type, id, source, e);
        }
    }

    @Override
    public void updateDocument(String id, Map<String, Object> source) {
        UpdateRequest request = new UpdateRequest(index, type, id);
        request.doc(source);
        try {
            restHighLevelClient.update(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            log.error("更新es的document[index={},type={},id={},source={}]异常:", index, type, id, source, e);
            throw new WorkException("更新es的document失败!");
        }
    }

    @Override
    public void deleteDocument(String type, String id) {
        try {
            DeleteRequest request = new DeleteRequest(index, type, id);
            restHighLevelClient.delete(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            log.error("删除es文档[index={},type={},id={}]异常:", index, type, id, e);
        }
    }

    @Override
    public void bulkDocument(String type, Map<String, Map<String, Object>> sources) {
        try {
            BulkRequest requests = new BulkRequest();
            Iterator<String> it = sources.keySet().iterator();
            int count = 0;
            while (it.hasNext()) {
                count++;
                String next = it.next();
                IndexRequest request = new IndexRequest(index, type, next);
                request.source(sources.get(next));
                requests.add(request);
                if (count % 1000 == 0) {
                    restHighLevelClient.bulk(requests, RequestOptions.DEFAULT);
                    requests.requests().clear();
                    count = 0;
                }
            }
            if (requests.numberOfActions() > 0) restHighLevelClient.bulk(requests, RequestOptions.DEFAULT);
        } catch (IOException e) {
            log.error("批量创建es文档[index={},type={},sources={}]异常:", index, type, sources, e);
        }
    }

    @Override
    public void bulkDeleteDocument(String type, List<Integer> ids) {
        try {
            BulkRequest requests = new BulkRequest();
            int count = 0;
            for (Integer id : ids) {
                count++;
                DeleteRequest request = new DeleteRequest(index, type, String.valueOf(id));
                requests.add(request);
                if (count % 1000 == 0) {
                    restHighLevelClient.bulk(requests, RequestOptions.DEFAULT);
                    requests.requests().clear();
                    count = 0;
                }
            }
            if (requests.numberOfActions() > 0) restHighLevelClient.bulk(requests, RequestOptions.DEFAULT);
        } catch (IOException e) {
            log.error("执行类[ElasticSearchServiceImpl]的方法[bulkDeleteDocument(...)]异常:", e);
        }
    }

    @Override
    public Page<Map<String, Object>> searchDocument(Page page, String keyword, String... fields) {
        SearchRequest request = new SearchRequest(index);
        SearchSourceBuilder builder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        try {
            boolQueryBuilder.should(QueryBuilders.matchPhraseQuery("content", keyword))
                    .should(QueryBuilders.matchPhraseQuery("title", keyword));
            builder.query(boolQueryBuilder);
            builder.from((int) ((page.getCurrent() - 1) * page.getSize())).size((int) page.getSize());
            request.source(builder);
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            long totalCount = response.getHits().getTotalHits();
            List<Map<String, Object>> records = Arrays.stream(response.getHits().getHits()).map(hit -> {
                Map<String, Object> map = new HashMap<>();
                map.put("id", hit.getId());
                map.putAll(hit.getSourceAsMap());
                return map;
            }).collect(Collectors.toList());
            page.setTotal(totalCount);
            page.setRecords(records);
            return page;
        } catch (IOException e) {
            log.error("es文档搜索[index={},type={},keyword={}]异常:", index, type, keyword, e);
            return new Page<>();
        }
    }

}

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值