ES(Elasticsearch)的应用与代码示例

发布于:2025-05-17 ⋅ 阅读:(22) ⋅ 点赞:(0)

Elasticsearch应用与代码示例技术文章大纲

一、引言
  1. Elasticsearch在现代化应用中的核心作用
  2. 典型应用场景分析(日志分析/全文检索/数据聚合)
二、环境准备(前提条件)
  1. Elasticsearch 8.x集群部署要点
  2. IK中文分词插件配置指南
  3. Ingest Attachment插件安装说明
三、核心代码结构解析
src/main/
├── java/
│   ├── config/
│   │   └── ElasticSearchConfig.java
│   ├── controller/
│   │   └── ElasticSearchController.java
│   ├── service/
│   │   ├── ElasticSearchService.java
│   │   └── ElasticSearchServiceImpl.java
│   ├── model/
│   │   ├── FileData.java
│   │   ├── Attachment.java
│   │   └── SearchResult.java
│   ├── dto/
│   │   └── WarningInfoDto.java
│   └── util/
│       └── ElasticSearchUtils.java
四、核心组件实现(含代码示例)

1. 配置中心(ElasticSearchConfig.java)
application.properties or yml

es.uri=192.168.1.1
es.port=9200
es.username=""
es.password=""
package com.zbxsoft.wds.config;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.json.JsonpMapper;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import com.alibaba.fastjson.parser.deserializer.JSONPDeserializer;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
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.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * es配置
 */
@Configuration
@ConfigurationProperties(prefix = "es")
public class ElasticSearchConfig{

    public String getUri() {
        return uri;
    }

    public void setUri(String uri) {
        this.uri = uri;
    }

    public Integer getPort() {
        return port;
    }

    public void setPort(Integer port) {
        this.port = port;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    private String uri;

    private Integer port;

    private String password;

    private String username;



    @Bean
    public ElasticsearchClient elasticsearchClient(@Autowired(required = false) JsonpMapper jsonpMapper, @Autowired(required = false) ObjectMapper objectMapper) {
        // 解析hostlist配置信息
        // 创建HttpHost数组,其中存放es主机和端口的配置信息
        HttpHost[] httpHostArray = new HttpHost[1];
        httpHostArray[0] = new HttpHost(uri,Integer.valueOf(port));

        RestClientBuilder builder = RestClient.builder(httpHostArray);

        final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        if(StringUtils.isNotBlank(username) && StringUtils.isNotBlank(password)){
            credentialsProvider.setCredentials(AuthScope.ANY,
                    new UsernamePasswordCredentials(username, password));
            RestClient client = RestClient.builder(new HttpHost(uri,Integer.valueOf(port)))
                        .build();
            ElasticsearchTransport transport = new RestClientTransport(client, new JacksonJsonpMapper());
            return new ElasticsearchClient(transport);
        }


        RestClient restClient = builder.build();

        ElasticsearchTransport transport = null;
        if (jsonpMapper != null) {
            transport = new RestClientTransport(restClient, jsonpMapper);
        } else if (objectMapper != null) {
            transport = new RestClientTransport(restClient, new JacksonJsonpMapper(objectMapper));
        } else {
            transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
        }
        // Create the transport with a Jackson mapper


        // And create the API client
        return new ElasticsearchClient(transport);
    }
}

2. 数据处理模型(FileData.java)

package com.zbxsoft.wds.config;


import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.zbxsoft.wds.fileupload.Attachment;
import lombok.Data;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;


import java.io.Serializable;
import java.util.Objects;

@Data
@Document(indexName = "file_data", createIndex = false)
@JsonIgnoreProperties(ignoreUnknown = true)
public class FileData implements Serializable {

    @Field(name = "file_id",type = FieldType.Text)
    private String file_id;

    @Field(name = "file_type",type = FieldType.Text)
    private String file_type;

    @Field(name = "file_name",type = FieldType.Text)
    private String file_name;

    @Field(name = "file_url",type = FieldType.Text)
    private String file_url;

    @Field(name = "file_size",type = FieldType.Text)
    private String file_size;

    @Field(name = "group_file_id",type = FieldType.Text)
    private String group_file_id;

    @Field(name = "file_suffix",type = FieldType.Text)
    private String file_suffix;

    @Field(name = "file_dir_name",type = FieldType.Text)
    private String file_dir_name;

    //保存时使用
    @Field(name = "attachment.content",type = FieldType.Text)
    private String content;

    //检索时使用
    private Attachment attachment;

}

}

3. 附件解析组件(Attachment.java)

package com.zbxsoft.wds.fileupload;


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

import java.io.Serializable;

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Attachment implements Serializable {


    private String date;

    private String content_type;

    private String author;

    private String language;

    private String title;

    private String content;

    private String content_length;
}

}

4. 服务层实现(ElasticSearchService.java)

package com.zbxsoft.wds.fileupload;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.zbxsoft.wds.config.FileData;
import org.springframework.http.HttpEntity;
import org.springframework.web.multipart.MultipartFile;

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

public interface ElasticsearchService {

    HttpEntity<?> createFileIndex(MultipartFile file) throws IOException;

    String createFileIndex(FileData fileData) throws IOException;

    Map<String,Double> queryWord(String keyword) throws IOException;

    IPage<SearchResult> queryWord(WarningInfoDto warningInfoDto) throws IOException;

    List<String> getAssociationalWordOther(WarningInfoDto warningInfoDto);

    String updateFileIndex(String id, FileData fileData) throws IOException;
}

工具类(ElasticSearchUtils.java)

package com.zbxsoft.wds.config;

import cn.hutool.extra.spring.SpringUtil;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.Result;
import co.elastic.clients.elasticsearch._types.SortOptions;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.aggregations.Aggregate;
import co.elastic.clients.elasticsearch._types.aggregations.Aggregation;
import co.elastic.clients.elasticsearch._types.mapping.DateProperty;
import co.elastic.clients.elasticsearch._types.mapping.Property;
import co.elastic.clients.elasticsearch._types.mapping.TextProperty;
import co.elastic.clients.elasticsearch._types.mapping.TypeMapping;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import co.elastic.clients.elasticsearch.core.*;
import co.elastic.clients.elasticsearch.core.bulk.BulkResponseItem;
import co.elastic.clients.elasticsearch.core.search.HitsMetadata;
import co.elastic.clients.elasticsearch.core.search.TotalHits;
import co.elastic.clients.elasticsearch.core.search.TotalHitsRelation;
import co.elastic.clients.elasticsearch.core.search.TrackHits;
import co.elastic.clients.elasticsearch.indices.*;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.io.StringReader;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
public class ElasticSearchUtils<T> {

    public static ElasticsearchClient elasticsearchClient;

    public String index;
    public Class obj;
    public String idField;
    public Set<String> fields;

    static {
        ElasticSearchConfig elasticSearchConfig = SpringUtil.getBean(ElasticSearchConfig.class);
//        elasticsearchClient = elasticSearchConfig.elasticsearchClient();
    }

    /**
     * 获取id字段
     *
     * @return
     */
    private String getIdValue(T t) throws Exception {
        Field field = t.getClass().getDeclaredField(idField);
        field.setAccessible(true);
        Object object = field.get(t);
        return object.toString();
    }


    /**
     * 判断索引是否存在
     *
     * @return
     */
    public Boolean getIndex() {
        try {
            GetIndexRequest getIndexRequest = GetIndexRequest.of(builder -> builder.index(index));
            GetIndexResponse getIndexResponse = elasticsearchClient.indices().get(getIndexRequest);
            log.info("getIndexResponse:{}", getIndexResponse);
            return true;
        } catch (IndexOutOfBoundsException | IOException e) {
            log.info("getIndexResponse:{}", e.getMessage());
            return false;
        }
    }

    public void deleteIndex() throws IOException {
        //1.创建索引请求
        DeleteIndexRequest request = DeleteIndexRequest.of(builder -> builder.index(index));
        //2.执行创建请求
        DeleteIndexResponse delete = elasticsearchClient.indices().delete(request);
        //如果为true就删除了
        log.info("DeleteIndexRequest:{}", delete);
    }
    /**
     * 插入数据
     *
     * @throws IOException
     */
    public void push(T t) throws Exception {
        String id = getIdValue(t);
        IndexRequest<T> indexRequest = IndexRequest.of(b -> b
                        .index(index)
                        .id(id)
                        .document(t)
                //刷新可以立刻搜索到,消耗性能
                /*.refresh(Refresh.True)*/);
        elasticsearchClient.index(indexRequest);
    }


    /**
     * 索引信息查询
     *
     * @throws IOException
     */
    public T query(String id) throws IOException {
        GetResponse<T> response = elasticsearchClient.get(g -> g
                        .index(index)
                        .id(id)
                , obj);
        if (response.found()) {
            return response.source();
        }
        return null;


    }



    /**
     * 索引信息查询
     *
     * @throws IOException
     */
    public HitsMetadata<T> queryList(int page, int pageSize, Query query, SortOptions... sortOptions) throws IOException {
        SearchResponse<T> search = elasticsearchClient.search(
                s -> s.index(index)
                        .query(query)
                        .trackTotalHits(TrackHits.of(i -> i.enabled(true)))
                        .sort(Arrays.asList(sortOptions))
                        .from((page - 1) * pageSize).size(pageSize)
                , obj);
        return search.hits();
    }

    /**
     * 删除文档
     *
     * @throws IOException
     */
    public boolean del(String id) throws IOException {
        DeleteResponse delete = elasticsearchClient.delete(
                d -> d.index(index)
                        .id(id));

        Result result = delete.result();
        return "deleted".equals(result.jsonValue()) | "not_found".equals(result.jsonValue());
    }

    /**
     * 批量
     *
     * @throws IOException
     */
    public Map<String, String> batchDel(Set<String> ids) throws Exception {
        BulkRequest.Builder br = new BulkRequest.Builder();
        for (String id : ids) {
            br.operations(op -> op.delete(d -> d.index(index).id(id)));
        }
        return requestBulk(br);
    }

    /**
     * 批量
     *
     * @throws IOException
     */
    public Map<String, String> batchAdd(List<T> list) throws Exception {
        BulkRequest.Builder br = new BulkRequest.Builder();
        for (T t : list) {
            String idValue = getIdValue(t);
            br.operations(op -> op
                    .index(idx -> idx
                            .index(index)
                            .id(idValue)
                            .document(t)
                    )
            );
        }
        return requestBulk(br);
    }

    /**
     * 处理批量请求
     *
     * @param br
     * @return
     * @throws IOException
     */
    private Map<String, String> requestBulk(BulkRequest.Builder br) throws IOException {
        //刷新可以立刻搜索到,消耗性能
        //br.refresh(Refresh.True);
        BulkResponse result = elasticsearchClient.bulk(br.build());
        System.out.println(result);
        Map<String, String> returnResult = new HashMap<>();
        if (result.errors()) {
            returnResult = result.items().stream()
                    .filter(e -> e.error() != null)
                    .collect(Collectors.toMap(BulkResponseItem::id, b -> b.error().reason()));
        }
        return returnResult;
    }

    /**
     * 分组
     * @param map
     * @return
     * @throws IOException
     */
    public Map<String, Aggregate> buildAggregate(Map<String, Aggregation> map) throws IOException {
        SearchResponse<T> search = elasticsearchClient.search(
                s -> s.index(index).size(0)
                        .aggregations(map), obj);
        return search.aggregations();
    }
    public Long queryCount(Query query) throws IOException {
        CountResponse search = elasticsearchClient.count(s -> s.index(index).query(query));
        return search.count();
    }

}

服务层实现(ElasticSearchServiceImpl.java)

package com.zbxsoft.wds.fileupload;
 
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.UUID;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch.core.*;
import co.elastic.clients.elasticsearch.core.search.*;

import com.aliyun.oss.ServiceException;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;


import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.zbxsoft.wds.aneo4j.TextAnalysis;
import com.zbxsoft.wds.aneo4j.rep.CustomNeo4jRepository;
import com.zbxsoft.wds.filequery.FileQuery;
import com.zbxsoft.wds.mapper.FileQueryMapper;
import com.zbxsoft.wds.config.FileData;
import com.zbxsoft.xwk.vo.R;
import lombok.extern.slf4j.Slf4j;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ResourceLoader;
import org.springframework.data.util.Pair;
import org.springframework.http.HttpEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;


import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.util.*;

@Service
@Slf4j
public class ElasticsearchServiceImpl implements ElasticsearchService {

    @Autowired
    private ElasticsearchClient client;

    @Autowired
    private ResourceLoader resourceLoader;

    @Autowired
    protected FileQueryMapper fileQueryMapper;

    @Value("${file.server.address}")
    private String fileServerAddress;

    @Autowired
    private CustomNeo4jRepository customNeo4jRepository;


    /**
     * 创建索引
     * @param fileData 文件数据
     * @return 索引id
     * @throws IOException exp
     */
    public String createFileIndex(FileData fileData) throws IOException {
        String path = fileData.getFile_url();
        String url = fileServerAddress + path;
        log.info("已上传文件地址:" + url);
        String fileName = FileUtil.getName(url);
        // 上传并返回新文件名称
        String prefix = fileName.substring(fileName.lastIndexOf(".") + 1);
        File file = File.createTempFile(fileName, prefix);
        IOUtils.copy(new URL(url),file);
        try (PDDocument document = PDDocument.load(file)) {
            //提取pdf中的文本内容
            PDFTextStripper pdfTextStripper = new PDFTextStripper();
            String text = pdfTextStripper.getText(document);

            //该主键 在es dm 中用作数据唯一id, 在neo4j中作为实体的type
            String id = fileData.getFile_id();
            //提取文章中的关键词
            List<String> keywords = TextAnalysis.getKeywords(text);
            if (CollectionUtil.isNotEmpty(keywords)) {
                //构建知识图谱
                customNeo4jRepository.buildArticleKeywordGraph(id, keywords);
                //更新keywords字段 file_id 就是数据库中存在的主键
                updateKeywords(id, String.join(",", keywords));
            }
        } catch (IOException e) {
            log.error("提取文本或创建关键词图谱失败,异常信息: {}", e.toString());
        }
        //最后建立该文章的索引
        String _docId = createIndex(file,fileData);
        return _docId;
    }

    /**
     * 更新文件对象的keyword
     * @param id 主键
     * @param keyword 关键词
     */
    private void updateKeywords(String id,String keyword){
        LambdaUpdateWrapper<FileQuery> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(FileQuery::getFileQueryId,id).set(FileQuery::getKeyword,keyword);
        fileQueryMapper.update(updateWrapper);
    }


    /**
     * 创建索引
     * @param file 文件
     * @param fileData 文件对象
     * @return 索引id
     */
    private String createIndex(File file, FileData fileData) {
        try {
            byte[] bytes = getContent(file);
            String base64 = Base64.getEncoder().encodeToString(bytes);
            fileData.setContent(base64);
            IndexRequest<Object> requestData = IndexRequest.of(i -> i.index("file_data").pipeline("attachment").id(fileData.getFile_id()).document(fileData));
            IndexResponse indexResponse = client.index(requestData);
            log.info("indexResponse:" + indexResponse);

            return indexResponse.id();
        } catch (IOException e) {
            log.error("文件上传异常,异常信息: {}", e.toString());
            return "";
        }
    }

    /**
     * 更新索引,在更新文件的时候发生
     * @param id 索引id 也是关系库主键
     * @param fileData 文件对象
     * @return
     * @throws IOException
     */
    @Override
    public String updateFileIndex(String id, FileData fileData) throws IOException {
        //直接删除索引, 重建
        DeleteRequest deleteRequest = DeleteRequest.of(s -> s.index("file_data").id(id));
        client.delete(deleteRequest);

        String _docId = createFileIndex(fileData);

        return _docId;

    }


    /**
     * 文件转base64
     *
     * @param file 文件对象
     * @return buffer
     * @throws IOException
     */
    private byte[] getContent(File file) throws IOException {
        long fileSize = file.length();
        if (fileSize > Integer.MAX_VALUE) {
            log.info("file too big...");
            return null;
        }
        FileInputStream fi = new FileInputStream(file);
        byte[] buffer = new byte[(int) fileSize];
        int offset = 0;
        int numRead = 0;
        while (offset < buffer.length
                && (numRead = fi.read(buffer, offset, buffer.length - offset)) >= 0) {
            offset += numRead;
        }
        // 确保所有数据均被读取
        if (offset != buffer.length) {
            throw new ServiceException("Could not completely read file "
                    + file.getName());
        }
        return buffer;
    }

    /**
     * 给定keyword 检索数据
     * @param keyword
     * @return
     * @throws IOException
     */
    public Map<String,Double> queryWord(String keyword) throws IOException {
        SearchResponse<FileData> response = doQuery(keyword);
        log.info("检索结果: {}", response.hits().hits());
        List<Pair<String,Double>> idList = Lists.newArrayList();
        Map<String,Double> idsWithScore = Maps.newHashMap();
        List<Hit<FileData>> hits = response.hits().hits();
        for (Hit<FileData> hit : hits) {
            Double score = hit.score();
            String id = hit.id();
            score = score == null ? 0.0d : score;
            idsWithScore.put(id,score);
        }

        log.info("查询数据: {}", idsWithScore);
        return idsWithScore;
    }


    /**
     * es attachment.content 检索封装
     * @param keyword 关键词
     * @return 检索结果
     * @throws IOException exp
     */
    private SearchResponse<FileData> doQuery(String keyword) throws IOException {

        Map<String, HighlightField> map = new HashMap<>();
        HighlightField build = new HighlightField.Builder().preTags("").postTags("").build();
        map.put("file_name",build);
        map.put("attachment.content",HighlightField.of(hf -> hf.preTags("").postTags("").numberOfFragments(4)));
        Highlight highlight = Highlight.of(h -> h
                .type(HighlighterType.of(ht -> ht
                        .builtin(BuiltinHighlighterType.Unified)))
                .fields(map)
                .fragmentSize(50).numberOfFragments(5));

        //索引 file_name 分词器 为ik_max_word 颗粒度较细  而attachment.content 使用ik_smart分词器 , 颗粒度相对粗一点
        SearchResponse<FileData> response = client.search(s -> s
                        .index("file_data")
                        .highlight(highlight)
                        .query(q -> q
                                .bool(b -> b
                                        .should(sh -> sh
                                                .match(t -> t
                                                        .field("file_name").query(keyword)))
                                        .should(sh -> sh
                                                .match(t -> t
                                                        .field("attachment.content").query(keyword)))

                                )),
                FileData.class);

        return response;
    }


    /**
     * 高亮分词搜索其它类型文档
     *
     * @param warningInfoDto
     * @return
     */
    public IPage<SearchResult> queryWord(WarningInfoDto warningInfoDto) throws IOException {
        //分页
        SearchResponse<FileData> response = doQuery(warningInfoDto.getKeyword());
        //手动创建分页对象
        IPage<SearchResult> warningInfoIPage = getFileDataIPage(warningInfoDto, response);

        return warningInfoIPage;
    }

    /**
     * 获取检索数据, 分页
     * @param warningInfoDto
     * @param response
     * @return
     */
    @NotNull
    private static IPage<SearchResult> getFileDataIPage(WarningInfoDto warningInfoDto, SearchResponse<FileData> response) {
        List<Hit<FileData>> hits = response.hits().hits();
        TotalHits total = response.hits().total();

        List<SearchResult> resultList = new LinkedList<>();
        //处理返回内容
        for (Hit<FileData> hit : hits) {
            Map<String, List<String>> map = hit.highlight();
            List<String> highLightWords = Lists.newArrayList();
            map.forEach((k,v) -> highLightWords.addAll(v));
            FileData fileData = hit.source();
            SearchResult searchResult = new SearchResult(fileData,highLightWords);
            resultList.add(searchResult);
        }

//        //设置一个最后需要返回的实体类集合
        //手动分页返回信息
        IPage<SearchResult> warningInfoIPage = new Page<>();
        assert total != null;
        warningInfoIPage.setTotal(total.value());
        warningInfoIPage.setRecords(resultList);
        warningInfoIPage.setCurrent(warningInfoDto.getPageIndex());
        warningInfoIPage.setSize(warningInfoDto.getPageSize());
        warningInfoIPage.setPages(warningInfoIPage.getTotal() % warningInfoDto.getPageSize());
        return warningInfoIPage;
    }




    /**
     * 文档信息关键词联想(根据输入框的词语联想文件名称)
     *
     * @param warningInfoDto
     * @return
     */

    public List<String> getAssociationalWordOther(WarningInfoDto warningInfoDto) {
//        //需要查询的字段
//        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
//                .should(QueryBuilders.matchBoolPrefixQuery("fileName", warningInfoDto.getKeyword()));
//        //contentType标签内容过滤
//        boolQueryBuilder.must(QueryBuilders.termsQuery("contentType", warningInfoDto.getContentType()));
//        //构建高亮查询
//        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
//                .withQuery(boolQueryBuilder)
//                .withHighlightFields(
//                        new HighlightBuilder.Field("fileName")
//                )
//                .withHighlightBuilder(new HighlightBuilder().preTags("<span style='color:red'>").postTags("</span>"))
//                .build();
//        //查询
//        SearchHits<FileData> search = null;
//        try {
//            search = client.search(searchQuery);
//        } catch (Exception ex) {
//            ex.printStackTrace();
//            throw new ServiceException(String.format("操作错误,请联系管理员!%s", ex.getMessage()));
//        }
//        //设置一个最后需要返回的实体类集合
//        List<String> resultList = new LinkedList<>();
//        //遍历返回的内容进行处理
//        for (org.springframework.data.elasticsearch.core.SearchHit<FileInfo> searchHit : search.getSearchHits()) {
//            //高亮的内容
//            Map<String, List<String>> highlightFields = searchHit.getHighlightFields();
//            //将高亮的内容填充到content中
//            searchHit.getContent().setFileName(highlightFields.get("fileName") == null ? searchHit.getContent().getFileName() : highlightFields.get("fileName").get(0));
//            if (highlightFields.get("fileName") != null) {
//                resultList.add(searchHit.getContent().getFileName());
//            }
//        }
//        //list去重
//        List<String> newResult = null;
//        if (!FastUtils.checkNullOrEmpty(resultList)) {
//            if (resultList.size() > 9) {
//                newResult = resultList.stream().distinct().collect(Collectors.toList()).subList(0, 9);
//            } else {
//                newResult = resultList.stream().distinct().collect(Collectors.toList());
//            }
//        }
        return new ArrayList<>();
    }


    /**
     * 上传文件并进行文件内容识别上传到es 测试使用
     * @param file
     * @return
     */
    public HttpEntity<?> createFileIndex(MultipartFile file) throws IOException {

        //http://192.168.100.243//file/wds/fileQuery/2024-12/1734319529179/downloadFile.pdf
//        InputStream inputStream = resourceLoader.getResource(url).getInputStream();
        String fileName = file.getName();
        String prefix = fileName.substring(fileName.lastIndexOf(".") + 1);
        File tempFile = File.createTempFile(fileName, prefix);
        // 上传文件路径
        file.transferTo(tempFile);

        FileData fileData = new FileData();

        fileData.setFile_url("http://localhost:9000/bucket/p2");
        fileData.setFile_id(UUID.fastUUID().toString(true));
        fileData.setFile_name("张飞吃豆芽333.pdf");
        fileData.setFile_suffix(".pdf");
        fileData.setFile_type("pdf");
        fileData.setFile_size("44");
        fileData.setFile_dir_name("p2");
        fileData.setGroup_file_id("g1");

        String _docId = createIndex(tempFile,fileData);

        return StringUtils.isBlank(_docId) ? R.badRequest("文件上传异常") : R.success("文件上传成功");

    }

}
五、数据传输

1. 前端请求数据传输(WarningInfoDto.java)

package com.zbxsoft.wds.fileupload;
 

import lombok.Data;
 
import java.util.List;
 
/**
 * 前端请求数据传输
 * WarningInfo
 * @author luoY
 */
@Data

public class WarningInfoDto{
    /**
     * 页数
     */

    private Integer pageIndex;
 
    /**
     * 每页数量
     */

    private Integer pageSize;
 
    /**
     * 查询关键词
     */
    private String keyword;
 
    /**
     * 内容类型
     */
    private List<String> contentType;
 
    /**
     * 用户手机号
     */
    private String phone;
}
}

2. 文档全文检索接口(ElasticSearchController.java)

package com.zbxsoft.wds.fileupload;
 
import com.baomidou.mybatisplus.core.metadata.IPage;

import com.zbxsoft.wds.common.R;

import org.springframework.http.HttpEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;


import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.List;
 
/**
 * es搜索引擎
 *
 * @author luoy
 */
@RestController
@RequestMapping("es")
public class ElasticsearchController {
    @Resource
    private ElasticsearchService elasticsearchService;


    @PostMapping("/uploadFile")
    public HttpEntity<?> uploadFile(@RequestParam(required = false) MultipartFile file) throws IOException {
        return elasticsearchService.createFileIndex(file);
    }


    /**
     * 告警信息关键词联想
     *
     * @param warningInfoDto
     * @return
     */
    @PostMapping("getAssociationalWordDoc")
    public HttpEntity<?> getAssociationalWordDoc(@RequestBody WarningInfoDto warningInfoDto, HttpServletRequest request) {
        List<String> words = elasticsearchService.getAssociationalWordOther(warningInfoDto);
        return R.list(words);
    }
 
 
    /**
     * 告警信息高亮分词分页查询
     *
     * @param warningInfoDto
     * @return
     */
    @PostMapping("queryHighLightWordDoc")
    public HttpEntity<?> queryHighLightWordDoc(@RequestBody WarningInfoDto warningInfoDto,HttpServletRequest request) throws IOException {
        IPage<SearchResult> warningInfoListPage = elasticsearchService.queryWord(warningInfoDto);
        return R.entity(warningInfoListPage);
    }
}

3. 数据返回(SearchResult.java)

package com.zbxsoft.wds.fileupload;

import com.zbxsoft.wds.config.FileData;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

import java.io.Serializable;
import java.util.List;

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class SearchResult implements Serializable {

    private FileData fileData;

    private List<String> highLightWords;
}

六、高级功能实现
  1. 多条件复合查询构建技巧
  2. 聚合统计实现方案
  3. 搜索高亮显示配置
七、性能优化建议
  1. 索引分片策略设计
  2. 查询DSL优化技巧
  3. 批量操作最佳实践
八、总结与展望
  1. 当前架构优势分析
  2. 后续演进方向建议

(注:各代码示例需配合完整的类定义和import语句,实际开发中需补充异常处理、日志记录等生产级代码要素)


网站公告

今日签到

点亮在社区的每一天
去签到