Spring Boot + Elasticsearch实现大批量数据集下中文的精确匹配-案例剖析
缘由
数据存储在MYSQ库中,数据基本维持不变,但数据量又较大(几千万)放在MYSQL中查询效率上较慢,寻求一种简单有效的方式提高查询效率,MYSQL并不擅长大规模数据量下的数据查询。
技术方案
考虑后期同样会使用到es,此次直接结合spring-boot框架形成一个独立服务,并不涉及UI展现内容,(ES版本2.4.5,5.0+版本的话就不能再使用spring data elasticsearch)技术组合如下:
Spring Boot+ Spring-data-elasticsearch + Elasticsearch
结合elasticsearch-jdbc插件,全量将数据一次性导入es中,后期不涉及数据变更。
es安装
测试期间单机安装,官网下载对应版本,由于笔者工作环境基于JDK7,所以下载5.0以下版本,5.0+均依赖Java8,同时使用到elasticsearch-jdbc插件,一并下载安装完成。
走过的大弯路
直接使用elasticsearch-jdbc工具,编写脚本文件,抽取数据到es中,脚本样例如下:
#!/bin/sh
DIR=
"$( cd "
$( dirname
"${BASH_SOURCE[0]}"
)
" && pwd )"
bin=${DIR}/../bin
lib=${DIR}/../lib
echo
'
{
"type": "jdbc",
"jdbc": {
"elasticsearch.autodiscover": true,
"url": "jdbc:mysql://192.168.1.3:3306/test",
"user": "root",
"password": "root",
"sql": "SELECT * from tb_name1",
"elasticsearch": {
"host": "192.168.1.1",
"port": 9300
},
"index": "my-index",
"type": "my-type"
}
}
'
| java \
-cp
"${lib}/*"
\
-
Dlog4j
.configurationFile=${bin}/log4j2.xml \
org.xbib.tools.
Runner
\
org.xbib.tools.
JDBCImporter
数据导入成功后,可使用head插件直接查看到。使用基本查询测试,查询条件是name=测试&num=100,使用精确匹配term语句,查询数据未果,实际使用num=100独立查询时,有相关数据。
问题跟踪解决
导致此现象的原因在于中文分词的问题,使用elasticsearch-jdbc脚本中并未处理列的mapping类型。(中间做过一次尝试,在脚本中定义对应的type_mapping,但并未成功,有兴趣的朋友可再做尝试)。
注:es与ik分词插件结合,版本匹配需要特别关注,但本案例并不涉及
结合此案例,查询时并不需要分词,而是精确匹配,但es默认情况下是指定string类型的分词,所以在index创建之前我们需要手动指定相关列不需要分词:not_analyzed,形如:
CURL -XPOST http:
//192.168.1.105:9200/my-index -d {
{
"mappings"
: {
"my-type"
: {
"properties"
: {
"name"
: {
"type"
:
"string"
,
"index"
:
"not_analyzed"
},
"num"
: {
"type"
:
"string"
,
"index"
:
"not_analyzed"
}
}
}
}
}
创建索引成功后,再使用elasticsearch-jdbc的脚本导入数据,相关数据列不会再使用分词分析,再使用term组合精确查询时,就可以查询相关数据来。
SpringBoot应用
pom.xml关键配置
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-data-elasticsearch
</artifactId>
</dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-web
</artifactId>
<exclusions>
<exclusion>
<artifactId>
log4j-over-slf4j
</artifactId>
<groupId>
org.slf4j
</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter
</artifactId>
<exclusions>
<exclusion>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-logging
</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-test
</artifactId>
<scope>
test
</scope>
</dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-log4j
</artifactId>
<version>
1.3.1.RELEASE
</version>
</dependency>
与elasticsearch交互实体
@Data
@Document
(indexName =
"my-index"
, type =
"my-type"
, shards =
5
, replicas =
1
, indexStoreType =
"fs"
, refreshInterval =
"-1"
)
public
class
DataBean
{
/**
* code:名称
*
* @since JDK 1.6
*/
public
String
name;
/**
* msg:编号
*
* @since JDK 1.6
*/
public
String
num;
}
与es交互接口类,返回数据的唯一_id值,若查得数据表示命中数据,若为空并未数据不存在
public
interface
DataBeanRepository
extends
ElasticsearchRepository
<
DataBean
,
Long
> {
//案例中并未使用,但可以用
public
List
<
BlackGreyData
> findByNameAndNum(
String
name,
String
num);
}
下面是业务处理层,采用BoolQueryBuilder构建查询条件,也即可基于DSL模块查询数据,还可以采用Criteria查询。
@Autowired
DataBeanRepository
repository;
@Override
public
List
<
DataBean
> query(
String
name,
String
num,
String
type) {
//采用过滤器的形式,提高查询效率
BoolQueryBuilder
builder =
QueryBuilders
.boolQuery();
builder.must(
QueryBuilders
.termQuery(
"name"
, name)).must(
QueryBuilders
.termQuery(
"num"
, num));
Iterable
<
DataBean
> lists = repository.search(builder);
List
<
DataBean
> datas =
new
ArrayList
<>();
for
(
DataBean
dataBean : lists) {
datas.add(dataBean);
logger.info(
"---------------------->>>Request result = 【"
+ dataBean +
"】"
);
}
return
datas;
}
其它再编写对应的请求响应逻辑,即可完成简单服务的完成。
测试结果
GPS数据量5000W+,精确匹配查询出来50条数据,耗时700ms左右,结果查询缓存机制,基本可以稳定在300ms左右。这也是在单节点,未作任何优化的情况的结果。
源码地址
https://github.com/backkoms/spring-boot-elasticsearch
扩展阅读:
成长的乐趣,在于分享!
|
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库