Elasticsearch 实战
需求
假设现在有这么一个需求,系统接了很多的报文,需要提供全文检索,为了简化,报文目前只有类型,流水号,内容这三个字段。
索引设计
建立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 实战的更多相关文章
- ElasticSearch实战-入门
http://www.cnblogs.com/smartloli/ 1.概述 今天接着<ElasticSearch实战-日志监控平台>一文来给大家分享后续的学习,在<ElasticS ...
- ElasticSearch实战-日志监控平台
1.概述 在项目业务倍增的情况下,查询效率受到影响,这里我们经过讨论,引进了分布式搜索套件——ElasticSearch,通过分布式搜索来解决当下业务上存在的问题.下面给大家列出今天分析的目录: El ...
- ElasticSearch实战
ElasticSearch实战-入门 1.概述 今天接着<ElasticSearch实战-日志监控平台>一文来给大家分享后续的学习,在<ElasticSearch实战-日志监控平台& ...
- ElasticSearch实战-编码实践
1.概述 前面在<ElasticSearch实战-入门>中给大家分享如何搭建这样一个集群,在完成集群的搭建后,今天给大家分享如何实现对应的业务功能模块,下面是今天的分享内容,目录如下所示: ...
- I-team 博客全文检索 Elasticsearch 实战
一直觉得博客缺点东西,最近还是发现了,当博客慢慢多起来的时候想要找一篇之前写的博客很是麻烦,于是作为后端开发的楼主觉得自己动手丰衣足食,也就有了这次博客全文检索功能Elasticsearch实战,这里 ...
- ElasticSearch实战系列二: ElasticSearch的DSL语句使用教程---图文详解
前言 在上一篇中介绍了ElasticSearch集群和kinaba的安装教程,本篇文章就来讲解下 ElasticSearch的DSL语句使用. ElasticSearch DSL 介绍 Elastic ...
- ElasticSearch实战系列三: ElasticSearch的JAVA API使用教程
前言 在上一篇中介绍了ElasticSearch实战系列二: ElasticSearch的DSL语句使用教程---图文详解,本篇文章就来讲解下 ElasticSearch 6.x官方Java API的 ...
- ElasticSearch实战系列四: ElasticSearch理论知识介绍
前言 在前几篇关于ElasticSearch的文章中,简单的讲了下有关ElasticSearch的一些使用,这篇文章讲一下有关 ElasticSearch的一些理论知识以及自己的一些见解. 虽然本人是 ...
- ElasticSearch实战系列五: ElasticSearch的聚合查询基础使用教程之度量(Metric)聚合
Title:ElasticSearch实战系列四: ElasticSearch的聚合查询基础使用教程之度量(Metric)聚合 前言 在上上一篇中介绍了ElasticSearch实战系列三: Elas ...
- ElasticSearch实战系列六: Logstash快速入门和实战
前言 本文主要介绍的是ELK日志系统中的Logstash快速入门和实战 ELK介绍 ELK是三个开源软件的缩写,分别表示:Elasticsearch , Logstash, Kibana , 它们都是 ...
随机推荐
- 【NOIP2013提高组】华容道
分析 一个比较显然的方式是 设 \(f_{i,j,x,y}\) 表示达到空格所处位置为 \((i,j)\) 且特殊格位置为 \(x,y\) 的状态的最少步数 一次可以交换空格和相邻格,代价为 \(1\ ...
- JZOJ 3528. 【NOIP2013模拟11.7A组】图书馆(library)
题目 解析 看到这题,没想到 \(dp\) 果断打了暴力 暴力理应只有 \(30\) 左右的样子 然而我加上了些奇技淫巧竟然有 \(80\) 分! 惊到我了! 我 \(80\) 分的暴力: 很容易想到 ...
- 钓鱼攻击之:WEB 钓鱼
郑重声明: 本笔记编写目的只用于安全知识提升,并与更多人共享安全知识,切勿使用笔记中的技术进行违法活动,利用笔记中的技术造成的后果与作者本人无关.倡导维护网络安全人人有责,共同维护网络文明和谐. 钓鱼 ...
- VScode本地搭建服务代码如何让其他人访问?
如本地开发域名访问: http://127.0.0.1:5500/pages/information/information.html?id=2259 想让别人访问: win+R -------> ...
- ASP.NET Core - 依赖注入(三)
4. 容器中的服务创建与释放 我们使用了 IoC 容器之后,服务实例的创建和销毁的工作就交给了容器去处理,前面也讲到了服务的生命周期,那三种生命周期中对象的创建和销毁分别在什么时候呢.以下面的例子演示 ...
- 下拉刷新,上拉触底(.js里自带)
<view>content值是{{cont}}</view> <button bindtap="add">+1</button> ...
- ARC157E XXYX Binary Tree 题解
首先,条件可以抽象为 Y 不能相连,然后: 钦定根为 Y,YX 的个数加上 \(2\): 钦定某一个叶子节点为 Y,XY 的个数加上 \(1\): 钦定某一个非叶子非根节点为 Y,YX 的个数加上 \ ...
- CF1383E 题解
题意 传送门 给定一个长度为 \(n\) 的 01 串 \(a\).在一次操作中,你可以选择任意一个 \(i\in[1,|a|)\),令 \(a_i=\max(a_i,a_{i+1})\),然后将 \ ...
- Kmeans中文聚类
中文文本kmeans聚类原理:K就是将原始数据分为K类,Means即均值点.K-Means的核心就是将一堆数据聚集为K个簇,每个簇中都有一个中心点称为均值点,簇中所有点到该簇的均值点的距离都较到其他簇 ...
- call, apply,bind的区别与用法
call, apply,bind的区别 相同点:都可以用来改变this指向 不同点: call, apply:传参方式不同: ...