需求

假设现在有这么一个需求,系统接了很多的报文,需要提供全文检索,为了简化,报文目前只有类型,流水号,内容这三个字段。

索引设计

建立msg索引,映射规则如下

PUT /msg
{
"mappings" : {
"properties" : {
"traceNo" : {
"type" : "keyword"
},
"type" : {
"type" : "keyword"
},
"content" : {
"type" : "text"
}
}
}
}

代码实现

交易VO

@Getter
@Setter
public class TradeVO { /**
* 交易编号
*/
private String tradeNo; /**
* 成交金额
*/
private Integer matchAmt; /**
* 成交数量
*/
private Integer matchQty; }

报文实体

package com.wangtao.msgsearch.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor; @NoArgsConstructor
@AllArgsConstructor
@Data
public class Msg { /**
* 0001: 交易所报文
* 0002: 银行间报文
* 0003: 场外报文
* es类型: keyword
*/
private String type; /**
* 流水号
* es类型: keyword
*/
private String traceNo; /**
* 报文内容
* es类型: text
*/
private String content; }

查询VO

package com.wangtao.msgsearch.vo;

import lombok.Data;
@Data
public class MsgSearchVO { /**
* 报文类型
*/
private String type; /**
* 流水号
*/
private String traceNo; /**
* 关键字, 从报文内容搜索
*/
private String keyword; private Integer pageNo = 1; private Integer pageSize = 20;
}

索引创建

/**
* 创建索引并指定映射
*/
@GetMapping("/createIndex")
public void createIndex() throws IOException {
TypeMapping typeMapping = new TypeMapping.Builder()
.properties("type", p -> p.keyword(k -> k))
.properties("traceNo", p -> p.keyword(k -> k))
.properties("content", p -> p.text(t -> t))
.build();
CreateIndexRequest createIndexRequest = new CreateIndexRequest.Builder()
.index(INDEX_NAME)
.mappings(typeMapping)
.build();
BooleanResponse booleanResponse = elasticsearchClient.indices().exists(e -> e.index(INDEX_NAME));
if (booleanResponse.value()) {
// 如果存在则删除
elasticsearchClient.indices().delete(d -> d.index(INDEX_NAME));
}
elasticsearchClient.indices().create(createIndexRequest);
}

插入测试数据

/**
* 准备数据
*/
private List<Msg> generateData() {
Random random = new Random();
List<Msg> msgList = new ArrayList<>();
for (int i = 1; i <= 50; i++) {
TradeVO tradeVO = new TradeVO();
tradeVO.setTradeNo("T20220821" + String.format("%03d", i));
tradeVO.setMatchAmt(random.nextInt(10000));
tradeVO.setMatchQty(tradeVO.getMatchAmt()); Msg msg = new Msg();
msg.setTraceNo("M20220821" + String.format("%03d", i));
msg.setType(MsgTypeEnum.ofOrdinal(i % 3).getValue());
try {
msg.setContent(objectMapper.writeValueAsString(tradeVO));
} catch (JsonProcessingException e) {
e.printStackTrace();
}
msgList.add(msg);
}
return msgList;
} /**
* 批量插入数据
*/
@GetMapping("/addData")
public List<Msg> addData() throws IOException {
List<Msg> msgList = generateData();
List<BulkOperation> bulkOperations = new ArrayList<>();
for (int i = 1; i <= msgList.size(); i++) {
Msg msg = msgList.get(i - 1);
String finalI = i + "";
BulkOperation bulkOperation = new BulkOperation.Builder()
.index(o -> o.id(finalI).document(msg))
.build();
bulkOperations.add(bulkOperation);
}
BulkRequest bulkRequest = new BulkRequest.Builder()
.index(INDEX_NAME)
.operations(bulkOperations)
.build();
BulkResponse response = elasticsearchClient.bulk(bulkRequest);
if (response.errors()) {
log.error("batch insert has error!");
}
return msgList;
}

根据条件搜索

@PostMapping("/searchByCondition")
public List<Msg> searchByCondition(@RequestBody MsgSearchVO msgSearchVO) throws IOException {
/*
* 类型为keyword时, 记录建立倒排索引时不会进行分词
* 查询时使用term关键字, 条件不会被分词
*
* 类型为text时, 记录建立倒排索引时会进行分词
* 查询时使用match关键字, 条件也会被分词
*/
log.info("args: {}", msgSearchVO);
Integer from = (msgSearchVO.getPageNo() - 1) * msgSearchVO.getPageSize();
List<Query> andQueryList = new ArrayList<>();
if (StringUtils.isNotBlank(msgSearchVO.getType())) {
Query byType = new TermQuery.Builder()
.field("type")
.value(msgSearchVO.getType())
.build()._toQuery();
andQueryList.add(byType);
}
if (StringUtils.isNotBlank(msgSearchVO.getTraceNo())) {
Query byTraceNo = new TermQuery.Builder()
.field("traceNo")
.value(msgSearchVO.getTraceNo())
.build()._toQuery();
andQueryList.add(byTraceNo);
}
if (StringUtils.isNotBlank(msgSearchVO.getKeyword())) {
Query byContent = new MatchQuery.Builder()
.field("content")
.query(msgSearchVO.getKeyword())
.build()._toQuery();
andQueryList.add(byContent);
}
Query query = new BoolQuery.Builder()
.must(andQueryList)
.build()._toQuery();
SearchResponse<Msg> response = elasticsearchClient.search(
s -> s.index(INDEX_NAME).from(from).size(msgSearchVO.getPageSize())
.query(query),
Msg.class
);
List<Hit<Msg>> hits = response.hits().hits();
assert response.hits().total() != null;
log.info("page count: {}", hits.size());
log.info("total count: {}", response.hits().total().value());
return hits.stream().map(Hit::source).collect(Collectors.toList());
}

源码

https://github.com/wangtaoj/elasticsearch-learning

Elasticsearch 实战的更多相关文章

  1. ElasticSearch实战-入门

    http://www.cnblogs.com/smartloli/ 1.概述 今天接着<ElasticSearch实战-日志监控平台>一文来给大家分享后续的学习,在<ElasticS ...

  2. ElasticSearch实战-日志监控平台

    1.概述 在项目业务倍增的情况下,查询效率受到影响,这里我们经过讨论,引进了分布式搜索套件——ElasticSearch,通过分布式搜索来解决当下业务上存在的问题.下面给大家列出今天分析的目录: El ...

  3. ElasticSearch实战

    ElasticSearch实战-入门 1.概述 今天接着<ElasticSearch实战-日志监控平台>一文来给大家分享后续的学习,在<ElasticSearch实战-日志监控平台& ...

  4. ElasticSearch实战-编码实践

    1.概述 前面在<ElasticSearch实战-入门>中给大家分享如何搭建这样一个集群,在完成集群的搭建后,今天给大家分享如何实现对应的业务功能模块,下面是今天的分享内容,目录如下所示: ...

  5. I-team 博客全文检索 Elasticsearch 实战

    一直觉得博客缺点东西,最近还是发现了,当博客慢慢多起来的时候想要找一篇之前写的博客很是麻烦,于是作为后端开发的楼主觉得自己动手丰衣足食,也就有了这次博客全文检索功能Elasticsearch实战,这里 ...

  6. ElasticSearch实战系列二: ElasticSearch的DSL语句使用教程---图文详解

    前言 在上一篇中介绍了ElasticSearch集群和kinaba的安装教程,本篇文章就来讲解下 ElasticSearch的DSL语句使用. ElasticSearch DSL 介绍 Elastic ...

  7. ElasticSearch实战系列三: ElasticSearch的JAVA API使用教程

    前言 在上一篇中介绍了ElasticSearch实战系列二: ElasticSearch的DSL语句使用教程---图文详解,本篇文章就来讲解下 ElasticSearch 6.x官方Java API的 ...

  8. ElasticSearch实战系列四: ElasticSearch理论知识介绍

    前言 在前几篇关于ElasticSearch的文章中,简单的讲了下有关ElasticSearch的一些使用,这篇文章讲一下有关 ElasticSearch的一些理论知识以及自己的一些见解. 虽然本人是 ...

  9. ElasticSearch实战系列五: ElasticSearch的聚合查询基础使用教程之度量(Metric)聚合

    Title:ElasticSearch实战系列四: ElasticSearch的聚合查询基础使用教程之度量(Metric)聚合 前言 在上上一篇中介绍了ElasticSearch实战系列三: Elas ...

  10. ElasticSearch实战系列六: Logstash快速入门和实战

    前言 本文主要介绍的是ELK日志系统中的Logstash快速入门和实战 ELK介绍 ELK是三个开源软件的缩写,分别表示:Elasticsearch , Logstash, Kibana , 它们都是 ...

随机推荐

  1. rin和快速迭代

    链接:https://ac.nowcoder.com/acm/contest/3002/E rin最近喜欢上了数论. 然而数论实在太复杂了,她只能研究一些简单的问题. 这天,她在研究正整数因子个数的时 ...

  2. python实现移动二级目录下的文件到一级目录

    python实现移动二级目录下的文件到一级目录 import os import shutil import sys def move_to_work_folder(work_path, cur_pa ...

  3. Android:LitePal 在第一次创建表之后第二次创建新的表不生效

    因为业务需求的增长,后续需要继续创建新的表,有可能代码没有任何报错,同时数据库也没有任何新的表加入进来. 修改 litepal.xml 的 version,如果之前是 1,那么修改为 2,总之比之前 ...

  4. 在 WXML 中使用 JS 代码

    {{}} 里面可以写任何的 JS 表达式,(一定是表达式,例如定义函数等都不属于表达式).例如,下面是在 wxml 中使用 JS 表达式: <view class="price tex ...

  5. node.js 中删除,修改等接口

    1.首先是引入模块.闯将服务器,设置路由等 二.查询员工接口 三.添加员工接口 四.删除员工接口 五.修改员工接口

  6. npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree

    VScode报错:npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree 不能解析依赖树 ,需要先修复上面 ...

  7. Markdown的学习方式

    Markdown的学习 标题 二级标题表示 \# + 标题名字 若是三级标题以及更多级标题根据\#的个数表示多少级 字体 ### 粗体: **+ 名字 +** **Hello World** 斜体: ...

  8. 常用的git提交代码命令

    日常开发使用的git提交代码的方法 一.初始化本地仓库,提交代码,提交到远程git仓库 1.初始化代码仓库git init2.将当前目录下的所有文件放到暂存区git add .3.查看文件状态git ...

  9. Deer_GF之【AssetsHotfix】和【AssetsNative】文件夹的区别

    Hi,今天介绍一下Deer_Gf里的[AssetsHotfix]和[AssetsNative]文件夹的区别:       框架介绍请移步[Deer_GF之框架介绍] 一.[AssetsHotfix] ...

  10. VUE学习-元素过渡

    单元素过渡 appear 初始渲染 通过 appear attribute 设置节点在初始渲染的过渡 appear + css <transition appear appear-class=& ...