当前位置: 首页 > news >正文

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

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;@Beanpublic 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 clientreturn 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 {@Autowiredprivate ElasticsearchClient client;@Autowiredprivate ResourceLoader resourceLoader;@Autowiredprotected FileQueryMapper fileQueryMapper;@Value("${file.server.address}")private String fileServerAddress;@Autowiredprivate 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中作为实体的typeString 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*/@Overridepublic 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*/@NotNullprivate 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*/
@Datapublic 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 {@Resourceprivate 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语句,实际开发中需补充异常处理、日志记录等生产级代码要素)

相关文章:

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

Elasticsearch应用与代码示例技术文章大纲 一、引言 Elasticsearch在现代化应用中的核心作用典型应用场景分析&#xff08;日志分析/全文检索/数据聚合&#xff09; 二、环境准备(前提条件) Elasticsearch 8.x集群部署要点IK中文分词插件配置指南Ingest Attachment插件安装…...

MinIO 开源的分布式文件服务器

如下是java代码调用MinIO的SDK实现文件的上传,并获取url <dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp</artifactId><version>4.9.3</version> <!-- 你可以选择4.8.1或更高版本 --></dependenc…...

蓝牙AVRCP协议概述

AVRCP(Audio/Video Remote Control Profile)定义了蓝牙设备和 audio/video 控制功能通信的特 点和过程&#xff0c;另用于远程控制音视频设备&#xff0c;底层传输基于 AVCTP 传输协议。该 Profile 定义了AV/C 数字命令控制集。命令和信息通过 AVCTP(Audio/Video Control Trans…...

【全网首发】解决coze工作流批量上传excel数据文档数据重复的问题

注意&#xff1a;目前方法将基于前一章批量数据库导入的修改&#xff01;&#xff01;&#xff01;&#xff01;请先阅读上篇文章的操作。抄袭注明来源 背景 上一节说的方法可以批量导入文件到数据库&#xff0c;但是无法解决已经上传的条目更新问题。简单来说&#xff0c;不…...

Hue面试内容整理-Hue 架构与前后端通信

Cloudera Hue 是一个基于 Web 的 SQL 助手,旨在为数据分析师和工程师提供统一的界面,以便与 Hadoop 生态系统中的各个组件(如 Hive、Impala、HDFS 等)进行交互。其架构设计强调前后端的分离与高效通信,确保系统的可扩展性和可维护性。以下是 Hue 架构及其前后端通信机制的…...

【八股战神篇】Java高频基础面试题

1 面向对象编程有哪些特性&#xff1f; 面向对象编程&#xff08;Object-Oriented Programming&#xff0c;简称 OOP&#xff09;是一种以对象为核心的编程范式&#xff0c;它通过模拟现实世界中的事物及其关系来组织代码。OOP 具有三大核心特性&#xff1a;封装、继承、多态。…...

matlab建立整车模型,求汽车的平顺性

在MATLAB中建立整车模型评估汽车平顺性&#xff0c;通常采用多自由度振动模型。以下是基于四分之一车模型的详细步骤和代码示例&#xff0c;可扩展至整车模型。 1. 四分之一车模型&#xff08;简化版&#xff09; 模型描述 自由度&#xff1a;2个&#xff08;车身垂直位移 z2…...

在Linux服务器上部署Jupyter Notebook并实现ssh无密码远程访问

Jupyter notebook版本7.4.2&#xff08;这个版本AI提示我Jupyter7&#xff08;底层是 jupyter_server 2.x&#xff09; 服务器开启服务 安装Jupyter notebook 7.4.2成功后&#xff0c;终端输入 jupyter notebook --generate-config 这将在 ~/.jupyter/ 目录下生成 jupyter_…...

C#数组与集合

&#x1f9e0; 一、数组&#xff08;Array&#xff09; 1. 定义和初始化数组 // 定义并初始化数组 int[] numbers new int[5]; // 默认值为 0// 声明并赋值 string[] names { "Tom", "Jerry", "Bob" };// 使用 new 初始化 double[] scores …...

服务器内部可以访问外部网络,docker内部无法访问外部网络,只能docker内部访问

要通过 iptables 将容器中的特定端口请求转发到特定服务器&#xff0c;你需要设置 DNAT&#xff08;目标地址转换&#xff09;规则。以下是详细步骤&#xff1a; 假设场景 容器端口: 8080&#xff08;容器内服务监听的端口&#xff09;目标服务器: 192.168.1.100&#xff08;请…...

mathematics-2024《Graph Convolutional Network for Image Restoration: A Survey》

推荐深蓝学院的《深度神经网络加速&#xff1a;cuDNN 与 TensorRT》&#xff0c;课程面向就业&#xff0c;细致讲解CUDA运算的理论支撑与实践&#xff0c;学完可以系统化掌握CUDA基础编程知识以及TensorRT实战&#xff0c;并且能够利用GPU开发高性能、高并发的软件系统&#xf…...

ssti刷刷刷

[NewStarCTF 公开赛赛道]BabySSTI_One 测试发现过滤关键字&#xff0c;但是特殊符号中括号、双引号、点都能用 可以考虑拼接或者编码&#xff0c;这里使用拼接 ?name{{()["__cla"~"ss__"]}}?name{{()["__cla"~"ss__"]["__ba&…...

Zephyr OS Nordic芯片的Flash 操作

目录 概述 1. 软硬件环境 1.1 软件开发环境 1.2 硬件环境 2 Flash操作库函数 2.1 nRF52832的Flash 2.2 Nordic 特有的 Flash 操作 2.2.1 nrfx_nvmc_bytes_write 函数 2.2.2 nrfx_nvmc_page_erase函数 2.2.3 nrfx_nvmc_write_done_check 函数 3 操作Flash的接口函数…...

傅里叶变换实战:图像去噪与边缘提取

傅里叶变换在图像处理中的应用与实践详解&#xff08;超详细教程实战代码&#xff09; &#x1f680; 本文从零开始详解傅里叶变换在图像处理中的应用&#xff0c;手把手教你实现图像去噪与边缘提取&#xff01;全文配套Python代码&#xff0c;新手也能轻松上手&#xff01; 一…...

go-中间件的使用

中间件介绍 Gin框架允许开发者在处理请求的过程中加入用户自己的钩子(Hook)函数这个钩子函数就是中间件&#xff0c;中间件适合处理一些公共的业务逻辑比如登录认证&#xff0c;权限校验&#xff0c;数据分页&#xff0c;记录日志&#xff0c;耗时统计 1.定义全局中间件 pac…...

昇腾NPU环境搭建

如果进入服务器输入npu-smi info可以看到npu情况&#xff0c;请直接跳转第三步 STEP1: 服务器安装依赖 sudo yum install -y gcc gcc-c make cmake unzip zlib-devel libffi-devel openssl-devel pciutils net-tools sqlite-devel lapack-devel gcc-gfortran python3-develyu…...

【HTML5学习笔记2】html标签(下)

1表格标签 1.1表格作用 显示数据 1.2基本语法 <table><tr> 一行<td>单元格1</td></tr> </table> 1.3表头单元格标签 表头单元格会加粗并且居中 <table><tr> 一行<th>单元格1</th></tr> </table&g…...

开源轻量级地图解决方案leaflet

Leaflet 地图&#xff1a;开源轻量级地图解决方案 Leaflet 是一个开源的 JavaScript 库&#xff0c;用于在网页中嵌入交互式地图。它以轻量级、灵活性和易用性著称&#xff0c;适用于需要快速集成地图功能的项目。以下是关于 Leaflet 的详细介绍和使用指南。 1. Leaflet 的核心…...

LLM学习笔记(六)线性代数

公式速查表 1. 向量与矩阵&#xff1a;表示、转换与知识存储的基础 向量表示 (Vectors): 语义的载体 在LLM中&#xff0c;向量 x ∈ R d \mathbf{x}\in\mathbb{R}^d x∈Rd 是信息的基本单元&#xff0c;承载着丰富的语义信息&#xff1a; 词嵌入向量 (Word Embeddings)&am…...

Vue 3.0双向数据绑定实现原理

Vue3 的数据双向绑定是通过响应式系统来实现的。相比于 Vue2&#xff0c;Vue3 在响应式系统上做了很多改进&#xff0c;主要使用了 Proxy 对象来替代原来的 Object.defineProperty。本文将介绍 Vue3 数据双向绑定的主要特点和实现方式。 1. 响应式系统 1.1. Proxy对象 Vue3 …...

Quasar组件 Carousel走马灯

通过对比两个q-carousel组件来&#xff0c;了解该组件的属性 官方文档请参阅&#xff1a;Carousel 预览 源代码 <template><div class"q-pa-md"><div class"q-gutter-md"><q-carouselv-model"slide"transition-prev&quo…...

Vue 2.0学习

个人简介 &#x1f468;‍&#x1f4bb;‍个人主页&#xff1a; 魔术师 &#x1f4d6;学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全栈发展 &#x1f6b4;个人状态&#xff1a; 研发工程师&#xff0c;现效力于政务服务网事业 &#x1f1e8;&#x1f1f3;人生格言&…...

LangFlow技术深度解析:可视化编排LangChain应用的新范式 -(3)组件系统

Component System | langflow-ai/langflow | DeepWiki 组件系统 相关源文件 组件系统是核心基础设施&#xff0c;使 Langflow 能够在工作流中创建、配置和连接模块化构建块。该系统通过为组件提供一致的接口来定义其输入、输出、执行行为以及与其他组件的连接&#xff0c;从…...

【Win32 API】 lstrcmpA()

作用 比较两个字符字符串&#xff08;比较区分大小写&#xff09;。 lstrcmp 函数通过从第一个字符开始检查&#xff0c;若相等&#xff0c;则检查下一个&#xff0c;直到找到不相等或到达字符串的末尾。 函数 int lstrcmpA(LPCSTR lpString1, LPCSTR lpString2); 参数 lpStr…...

LabVIEW光谱检测系统

腔衰荡光谱技术&#xff08;CRDS&#xff09;凭借高精度和高灵敏度特性&#xff0c;成为微量气体浓度检测的常用方法&#xff0c;而准确获取衰荡时间是该技术应用的关键。基于LabVIEW平台设计腔衰荡信号在线处理系统&#xff0c;实现对衰荡信号的实时采集、平均、拟合、显示和保…...

深入解读WPDRRC信息安全模型:构建中国特色的信息安全防护体系

目录 前言1 WPDRRC模型概述2 模型结构详解2.1 预警&#xff08;Warning&#xff09;2.2 保护&#xff08;Protect&#xff09;2.3 检测&#xff08;Detect&#xff09;2.4 响应&#xff08;React&#xff09;2.5 恢复&#xff08;Restore&#xff09;2.6 反击&#xff08;Count…...

uniapp-商城-59-后台 新增商品(属性的选中,进行过滤展示,filter,some,every和map)

前面讲了属性的添加&#xff0c;添加完成后&#xff0c;数据库中已经存在数据了&#xff0c;这时再继续商品的添加时&#xff0c;就可以进行属性的选择了。 在商品添加过程中&#xff0c;属性选择是一个关键步骤。首先&#xff0c;界面需要展示嵌套的属性数据&#xff0c;用户通…...

RDIFramework.NET Web敏捷开发框架 V6.2发布(.NET6+、Framework双引擎)

1、框架介绍 .NET6、Framework双引擎、全网唯一 RDIFramework.NET敏捷开发框架&#xff0c;是我司重磅推出的支持.NET6和.NET Framework双引擎的快速信息化系统开发、整合框架&#xff0c;为企业快速构建企业级的应用提供了强大支持。 依托框架强大的基座&#xff0c;开发人员只…...

JMeter 教程:编写 GET 请求脚本访问百度首页

目录 练习要求&#xff1a; 练习步骤&#xff1a; 效果图&#xff1a; 练习要求&#xff1a; 练习步骤&#xff1a; 效果图&#xff1a;...

JSP 实现二级联动下拉菜单:一次加载,前端动态更新

在Web开发中,二级联动下拉菜单(或多级联动)是一种非常常见的用户交互形式,例如选择省份后动态加载对应的城市列表。本文将详细介绍一种在JSP中实现二级联动的方法:后端一次性将所有联动数据加载到前端,然后通过JavaScript在客户端动态更新二级下拉菜单。这种方法对于数据…...

Room数据库

Room数据库 Room是Android Jetpack组件中的一款SQLite数据库抽象层框架&#xff0c;旨在简化本地数据库操作&#xff0c;提供编译时SQL校验、类型与安全、与LiveData/Flow无缝集成等特性。 1. 什么是Room 定义&#xff1a; Room 是 Android Jetpack 提供的一个 ORM&#xff…...

文件上传Ⅲ

#文件-解析方案-执行权限&解码还原 1、执行权限 文件上传后存储目录不给执行权限&#xff08;即它并不限制你上传文件的类型&#xff0c;但不会让相应存有后门代码的PHP文件执行&#xff0c;但是PNG图片是可以访问的&#xff09; 2、解码还原 数据做存储&#xff0c;解…...

前端取经路——量子UI:响应式交互新范式

嘿&#xff0c;老铁们好啊&#xff01;我是老十三&#xff0c;一枚普通的前端切图仔&#xff08;不&#xff0c;开玩笑的&#xff0c;我是正经开发&#xff09;。最近前端技术简直跟坐火箭一样&#xff0c;飞速发展&#xff01;今天我就跟大家唠唠从状态管理到实时渲染&#xf…...

15 C 语言字符类型详解:转义字符、格式化输出、字符类型本质、ASCII 码编程实战、最值宏汇总

1 字符类型概述 在 C 语言中&#xff0c;字符类型 char 用于表示单个字符&#xff0c;例如一个数字、一个字母或一个符号。 char 类型的字面量是用单引号括起来的单个字符&#xff0c;例如 A、5 或 #。 当需要表示多个字符组成的序列时&#xff0c;就涉及到了字符串。在 C 语言…...

AlphaEvolve:LLM驱动的算法进化革命与科学发现新范式

AlphaEvolve&#xff1a;LLM驱动的算法进化革命与科学发现新范式 本文聚焦Google DeepMind最新发布的AlphaEvolve&#xff0c;探讨其如何通过LLM与进化算法的结合&#xff0c;在数学难题突破、计算基础设施优化等领域实现革命性进展。从48次乘法优化44矩阵相乘到数据中心资源利…...

比较文本搜索策略 pgsearch、tsvector 和外部引擎

大家好&#xff0c;这里是架构资源栈&#xff01;点击上方关注&#xff0c;添加“星标”&#xff0c;一起学习大厂前沿架构&#xff01; 在应用程序中实现搜索功能时&#xff0c;您需要选择合适的文本搜索方法。本指南比较了 PostgreSQL 的内置搜索引擎tsvector、pg_search扩展…...

58. 区间和

题目链接&#xff1a; 58. 区间和 题目描述&#xff1a; 给定一个整数数组 Array&#xff0c;请计算该数组在每个指定区间内元素的总和。 输入描述 第一行输入为整数数组 Array 的长度 n&#xff0c;接下来 n 行&#xff0c;每行一个整数&#xff0c;表示数组的元素。随后…...

MySQL中表的增删改查(CRUD)

一.在表中增加数据&#xff08;Create&#xff09; INSERT [INTO] TB_NAME [(COLUMN1,COLUMN2,...)] VALUES (value_list1),(value_list2),...;into可以省略可仅选择部分列选择插入&#xff0c;column即选择的列&#xff0c; 如图例可以选择仅在valuelist中插入age和id如果不指…...

SQL练习(6/81)

目录 1.寻找连续值 方法一&#xff1a;使用自连接&#xff08;Self-Join&#xff09; 方法二&#xff1a;使用窗口函数&#xff08;Window Functions&#xff09; 2.寻找有重复的值 GROUP BY子句 HAVING子句 常用聚合函数&#xff1a; 3.找不存在某属性的值 not in no…...

Android 中 打开文件选择器(ACTION_OPEN_DOCUMENT )

在 Android 中&#xff0c;打开文件选择器&#xff08;File Picker&#xff09;通常是指启动一个系统提供的界面&#xff0c;让用户可以选择存储在设备上的文件。可以通过发送一个带有 Intent.ACTION_OPEN_DOCUMENT 或 Intent.ACTION_GET_CONTENT 的 Intent 来实现。 1、启动文…...

AWS中国区CloudFront证书管理和应用指南

在AWS中国区使用CloudFront时,SSL/TLS证书的管理和应用是一个重要的环节。本文将详细介绍如何在AWS中国区上传、管理和应用SSL证书到CloudFront分配。 1. 准备证书文件 首先,我们需要准备好SSL证书相关的文件。通常,这包括: 私钥文件(.key)公钥证书文件(.crt)证书链文…...

Python之三大基本库——Matplotlib

好久没来总结了&#xff0c;今天刚好有时间&#xff0c;我们来继续总结一下python中的matplotlib 一、什么是Matplotlib ‌Matplotlib‌是一个Python的2D绘图库&#xff0c;主要用于将数据绘制成各种图表&#xff0c;如折线图、柱状图、散点图、直方图、饼图等。它以各种硬拷贝…...

随笔:hhhhh

第一题 ∫ − ∞ ∞ x e x − e x d x ∫ 0 ∞ ln ⁡ t ⋅ e ln ⁡ t − t ⋅ 1 t d t ∫ 0 ∞ ln ⁡ t ⋅ e − t ⋅ 1 t ⋅ t d t ∫ 0 ∞ ln ⁡ t ⋅ e − t d t ψ ( 1 ) − γ \begin{align*} \int_{-\infty}^{\infty}xe^{x-e^x}\text{d}x&\int_{0}^{\infty}…...

计算机网络-----6分层结构

目录 “分层” 的设计思想&#xff1a; 计算机网络要完成的功能&#xff1a; 计算机网络的分层结构&#xff1a; 网络体系结构的概念&#xff1a; 各层之间的关系&#xff1a; 数据的传输过程 水平视角&#xff1a; 垂直视角&#xff1a; 相关概念 协议三要素&#x…...

初识SOC:RK3588

目录 一、高性能计算与边缘计算 二、多媒体处理与显示 三、图形与游戏开发 四、物联网与嵌入式系统 五、操作系统兼容性 RK3588作为瑞芯微推出的高性能处理器&#xff0c;凭借其多核架构、高算力NPU和多媒体处理能力&#xff0c;可广泛应用于以下领域&#xff1a; 一、高…...

卡顿检测与 Choreographer 原理

一、卡顿检测的原理 卡顿的本质是主线程&#xff08;UI 线程&#xff09;未能及时完成某帧的渲染任务&#xff08;超过 16.6ms&#xff0c;以 60Hz 屏幕为例&#xff09;&#xff0c;导致丢帧&#xff08;Frame Drop&#xff09;。检测卡顿的核心思路是监控主线程任务的执行时…...

第十天——贪心算法——深度总结

文章目录 贪心算法深度解析&#xff1a;原理与应用 1. 贪心算法的基本原理 1.1 贪心选择性质 1.2 最优子结构 1.3 贪心算法与动态规划的对比 2. 贪心算法的应用场景 3. 具体应用案例 3.1 分配饼干 (Assign Cookies) 3.2 分糖果 (Candy Distribution) 3.3 种花问题 (C…...

python自学笔记2 数据类型

字符串操作 f字符串&#xff1a; for index, char in enumerate(greeting_str):print(f"字符&#xff1a;{char}, 索引&#xff1a;{index}")f字符串可以方便的在字符串中插入变量 字符串切片 指定步长&#xff1a; print(greeting_str[::2])指定步长为2的取字符…...

nacos配置文件快速部署另一种方法

提交nacos配置的另一种一种方法,批命令/shell: 以下脚本直接把当前目录下的所有yaml文件一键提交到nacos上 前提是要先安装curl 以及 jq 然后 把下面的shell保存为 import-all.sh 然后 chmod x import-all.sh && ./import-all.sh 就好了. 记得修改一下的NAMESPACE_…...

RTK哪个品牌好?2025年RTK主流品牌深度解析

在测绘领域&#xff0c;RTK 技术的发展日新月异&#xff0c;选择一款性能卓越、稳定可靠的 RTK 设备至关重要。2025 年&#xff0c;市场上涌现出众多优秀品牌&#xff0c;本文将深入解析几大主流品牌的核心竞争力。 华测导航&#xff08;CHCNAV&#xff09;&#xff1a;技术创…...