缘由

数据存储在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中,脚本样例如下:

  1. #!/bin/sh
  2. DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
  3. bin=${DIR}/../bin
  4. lib=${DIR}/../lib
  5. echo '
  6. {
  7.    "type": "jdbc",
  8.    "jdbc": {
  9.        "elasticsearch.autodiscover": true,
  10.        "url": "jdbc:mysql://192.168.1.3:3306/test",
  11.        "user": "root",
  12.        "password": "root",
  13.        "sql": "SELECT * from tb_name1",
  14.        "elasticsearch": {
  15.            "host": "192.168.1.1",
  16.            "port": 9300
  17.        },
  18.        "index": "my-index",
  19.        "type": "my-type"
  20.    }
  21. }
  22. ' | java \
  23.    -cp "${lib}/*" \
  24.    -Dlog4j.configurationFile=${bin}/log4j2.xml \
  25.    org.xbib.tools.Runner \
  26.    org.xbib.tools.JDBCImporter

数据导入成功后,可使用head插件直接查看到。使用基本查询测试,查询条件是name=测试&num=100,使用精确匹配term语句,查询数据未果,实际使用num=100独立查询时,有相关数据。

问题跟踪解决

导致此现象的原因在于中文分词的问题,使用elasticsearch-jdbc脚本中并未处理列的mapping类型。(中间做过一次尝试,在脚本中定义对应的type_mapping,但并未成功,有兴趣的朋友可再做尝试)。

注:es与ik分词插件结合,版本匹配需要特别关注,但本案例并不涉及

结合此案例,查询时并不需要分词,而是精确匹配,但es默认情况下是指定string类型的分词,所以在index创建之前我们需要手动指定相关列不需要分词:not_analyzed,形如:

  1. CURL -XPOST http://192.168.1.105:9200/my-index -d {
  2.    {
  3.    "mappings": {
  4.        "my-type": {
  5.            "properties": {
  6.                "name": {
  7.                    "type": "string",
  8.                    "index": "not_analyzed"
  9.                },
  10.                "num": {
  11.                    "type": "string",
  12.                    "index": "not_analyzed"
  13.                }
  14.            }
  15.        }
  16.    }
  17. }

创建索引成功后,再使用elasticsearch-jdbc的脚本导入数据,相关数据列不会再使用分词分析,再使用term组合精确查询时,就可以查询相关数据来。

SpringBoot应用

pom.xml关键配置

  1. <dependency>
  2.    <groupId>org.springframework.boot</groupId>
  3.    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
  4. </dependency>
  5. <dependency>
  6.    <groupId>org.springframework.boot</groupId>
  7.    <artifactId>spring-boot-starter-web</artifactId>
  8.    <exclusions>
  9.        <exclusion>
  10.            <artifactId>log4j-over-slf4j</artifactId>
  11.            <groupId>org.slf4j</groupId>
  12.        </exclusion>
  13.    </exclusions>
  14. </dependency>
  15. <dependency>
  16.    <groupId>org.springframework.boot</groupId>
  17.    <artifactId>spring-boot-starter</artifactId>
  18.    <exclusions>
  19.        <exclusion>
  20.            <groupId>org.springframework.boot</groupId>
  21.            <artifactId>spring-boot-starter-logging</artifactId>
  22.        </exclusion>
  23.    </exclusions>
  24. </dependency>
  25. <dependency>
  26.    <groupId>org.springframework.boot</groupId>
  27.    <artifactId>spring-boot-starter-test</artifactId>
  28.    <scope>test</scope>
  29. </dependency>
  30. <dependency>
  31.    <groupId>org.springframework.boot</groupId>
  32.    <artifactId>spring-boot-starter-log4j</artifactId>
  33.    <version>1.3.1.RELEASE</version>
  34. </dependency>

与elasticsearch交互实体

  1. @Data
  2. @Document(indexName = "my-index", type = "my-type", shards = 5, replicas = 1, indexStoreType = "fs", refreshInterval = "-1")
  3. public class DataBean {
  4.    /**
  5.     * code:名称
  6.     *
  7.     * @since JDK 1.6
  8.     */
  9.    public String name;
  10.    /**
  11.     * msg:编号
  12.     *
  13.     * @since JDK 1.6
  14.     */
  15.    public String num;
  16. }

与es交互接口类,返回数据的唯一_id值,若查得数据表示命中数据,若为空并未数据不存在

  1. public interface DataBeanRepository extends ElasticsearchRepository<DataBean, Long> {
  2.    //案例中并未使用,但可以用
  3.    public List<BlackGreyData> findByNameAndNum(String name, String num);
  4. }

下面是业务处理层,采用BoolQueryBuilder构建查询条件,也即可基于DSL模块查询数据,还可以采用Criteria查询。

  1. @Autowired
  2.    DataBeanRepository repository;
  3.    @Override
  4.    public List<DataBean> query(String name, String num, String type) {
  5.        //采用过滤器的形式,提高查询效率
  6.        BoolQueryBuilder builder = QueryBuilders.boolQuery();
  7.        builder.must(QueryBuilders.termQuery("name", name)).must(QueryBuilders.termQuery("num", num));
  8.        Iterable<DataBean> lists = repository.search(builder);
  9.        List<DataBean> datas = new ArrayList<>();
  10.        for (DataBean dataBean : lists) {
  11.            datas.add(dataBean);
  12.            logger.info("---------------------->>>Request result = 【" + dataBean + "】");
  13.        }
  14.        return datas;
  15.    }

其它再编写对应的请求响应逻辑,即可完成简单服务的完成。

测试结果

GPS数据量5000W+,精确匹配查询出来50条数据,耗时700ms左右,结果查询缓存机制,基本可以稳定在300ms左右。这也是在单节点,未作任何优化的情况的结果。

源码地址

https://github.com/backkoms/spring-boot-elasticsearch

扩展阅读:

Spring Boot + Elasticsearch实现大批量数据集下中文的精确匹配-案例剖析的更多相关文章

  1. Spring Boot + Elasticsearch 实现索引批量写入

    在使用Eleasticsearch进行索引维护的过程中,如果你的应用场景需要频繁的大批量的索引写入,再使用上篇中提到的维护方法的话显然效率是低下的,此时推荐使用bulkIndex来提升效率.批写入数据 ...

  2. Spring Boot + Elasticsearch 实现索引的日常维护

    全文检索的应用越来越广泛,几乎成了互联网应用的标配,商品搜索.日志分析.历史数据归档等等,各种场景都会涉及到大批量的数据,在全文检索方面,方案无外乎Lucene.Solr.Elasticsearch三 ...

  3. Spring Boot + Elasticsearch

    spring data elasticsearch elasticsearch 2.0.0.RELEASE 2.2.0 1.4.0.M1 1.7.3 1.3.0.RELEASE 1.5.2 1.2.0 ...

  4. 解决Spring boot中读取属性配置文件出现中文乱码的问题

    问题描述: 在配置文件application.properties中写了 server.port=8081 server.servlet.context-path=/boy name=张三 age=2 ...

  5. 搭建spring boot+elasticsearch+activemq服务

    目前时间是:2017-01-24 本文不涉及activemq的安装 需求 activemq实时传递数据至服务 elasticsearch做索引 对外开放查询接口 完成全文检索 环境 jdk:1.8 s ...

  6. Spring Boot Document Part II(下)

    Part II. Getting started 11. 开发第一个Spirng Boot Application使用Spring Boot的关键特征开发一个基于JAVA Web的“Hello Wor ...

  7. spring boot web项目在IDEA下热部署解决办法(四步搞定)

    最近在用spring boot 做一个web站点,修改了类.html.js等,刷新页面,没有生效,非要手动去make一下或者重启,大大降低了开发效率. 什么是热部署? 应用启动后会把编译好的Class ...

  8. spring boot 在jdk 1.7下使用 commandLineRunner

    在spring boot 中有一段代码,使用的是java 1.8的语法: @Bean public CommandLineRunner commandLineRunner(ApplicationCon ...

  9. Spring Boot 2.2.2.RELEASE 版本中文参考文档【3.1】

    使用Spring Boot 本节将详细介绍如何使用Spring Boot.它涵盖了诸如构建系统,自动配置以及如何运行应用程序之类的主题.我们还将介绍一些Spring Boot最佳实践.尽管Spring ...

随机推荐

  1. .NET VS 自定义新建代码文件模板

    参考:http://www.cnblogs.com/fightingtong/p/3765914.html 在VS中新建文件时,可使用模板在文件中生成指定内容.只需要把IDE安装目录下的模板进行修改保 ...

  2. ADB 基础命令使用

    1.adb shell(>=2个设备显示:error: more than one device/emulator,仅连接一个设备可用) adb -d shell 只运行在真实设备中 adb - ...

  3. xen学习(一)

    添加镜像源 [root@xen xen]# cat /etc/yum.repos.d/xen.repo [xen] name=xenserver baseurl=http://mirrors.163. ...

  4. AngularJS 1.4对动画系统进行了彻底的重构

    分享 <关于我> 分享  [中文纪录片]互联网时代                 http://pan.baidu.com/s/1qWkJfcS 分享 <HTML开发MacOSAp ...

  5. 发布Qt Quick桌面应用程序的方法(使得planets在XP上运行)

    发布Qt Quick桌面应用程序的方法 Qt是一款优秀的跨平台开发框架,它可以在桌面.移动平台以及嵌入式平台上运行.目前Qt 5介绍程序发布的文章帖子比较少.大家又非常想要知道如何发布Qt应用程序,于 ...

  6. 在不开启事件循环的线程中使用QTimer(QThread::run函数自带事件循环,在构造函数里创建线程,是一种很有意思的线程用法) good

    引入 QTimer是Qt自带的定时器类,QTimer运行时是依赖于事件循环的,简单来说,在一个不开启事件循环(未调用exec() )的线程中,QTimer是无法使用的.通过分析Qt源码可发现,调用QT ...

  7. SilverlightMVVM模式中的数据校验

    silverlight的数据校验大体分成3种类型: 数据是非必填的但是需要满足相应数据格式的 数据是必填的且可能需要进行数据格式校验的 其他(如数据的联动校验) 以下的数据校验方式针对第二种: 在相应 ...

  8. [2017.02.15] 《C++Primer5》 复习笔记

    编程语言主要是提供一个框架,用计算机能够处理的方式来表达问题的解决方法. 自定义数据类型class的基本思想是数据抽象dataabstraction和封装encapsulation.数据抽象是一种依赖 ...

  9. kubernetes实战篇之nexus oss服务器部署及基于nexus的docker镜像仓库搭建

    系列目录 Nexus oss仓库管理平台搭建 Nexus是一款仓库管理工具,支持Npm,bower,maven,nuget,apt,yum甚至docker,helm等各种仓库,说的通俗以下,就是私服镜 ...

  10. 程序代写, CS代写, 代码代写, CS编程代写, java代写, python代写, c++/c代写, R代写, 算法代写, web代写

    互联网一线工程师程序代写 微信联系 当天完成 查看大牛简介特色: 学霸代写,按时交付,保证原创,7*24在线服务,可加急.用心代写/辅导/帮助客户CS作业. 客户反馈与评价 服务质量:保证honor ...