前言

  • 前面两边文章已经讲述了如何搭建集群以及简单的查询基础,想看的移步:

1. Elasticsearch 5.5 入门必会(一)

2. Elasticsearch 5.5 入门必会之Java client(二)

一、怎样用SQL思维来写查询代码

  • 写惯了SQL然后来写ES的查询可能有很别扭,ES其实也提供了queryStringQuery的方式来查询,这个查询和SQL有点接近了,但是本文还是用普通代码方式达到SQL关系查询的逻辑

我们先看个简单的代码:

 @Testpublic void match() {SearchRequestBuilder requestBuilder = client.prepareSearch("megacorp").setTypes("employee").setQuery(QueryBuilders.matchQuery("about", "rock climbing"));System.out.println(requestBuilder.toString());SearchResponse response = requestBuilder.execute().actionGet();System.out.println(response.status());if (response.status().getStatus() == 200) {for (SearchHit hits : response.getHits().getHits()) {System.out.println(hits.getSourceAsString());}}}

===============================================================

  • LIKE查询 这个代码其实在普通的SQL里面是达不到这个效果的,因为matchQuery会对后面的value进行分词后再去匹配,跳过!
 /*** matchphrase使用,短语精准匹配*/@Testpublic void matchPhrase() {SearchRequestBuilder requestBuilder = client.prepareSearch("megacorp").setTypes("employee").setQuery(QueryBuilders.matchPhraseQuery("about", "rock climbing"));System.out.println(requestBuilder.toString());SearchResponse response = requestBuilder.execute().actionGet();System.out.println(response.status());if (response.status().getStatus() == 200) {for (SearchHit hits : response.getHits().getHits()) {System.out.println(hits.getSourceAsString());}}}

上面的代码你可以理解为:

select * from megacorp_employee where about like '%rock climbing%'
  • 聚合查询
@Testpublic void aggregation() {SearchRequestBuilder searchBuilder = client.prepareSearch("megacorp").setTypes("employee").addAggregation(AggregationBuilders.terms("by_interests").field("interests").subAggregation(AggregationBuilders.terms("by_age").field("age")).size(10));System.out.println(searchBuilder.toString());SearchResponse response = searchBuilder.execute().actionGet();if (response.status().getStatus() == 200) {for (SearchHit hits : response.getHits().getHits()) {System.out.println(hits.getSourceAsString());}}StringTerms terms = response.getAggregations().get("by_interests");for (StringTerms.Bucket bucket : terms.getBuckets()) {System.out.println("-interest:" + bucket.getKey() + "," + bucket.getDocCount());if (bucket.getAggregations() != null && bucket.getAggregations().get("by_age") != null) {LongTerms ageTerms = bucket.getAggregations().get("by_age");for (LongTerms.Bucket bucket2 : ageTerms.getBuckets()) {System.out.println("--------by age:" + bucket2.getKey() + "," + bucket2.getDocCount());}}}}

相当于SQL里面的

select interests,age,count(1) from megacorp_employee
group by interests,age limit 10
  • 布尔查询
BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();if(StringUtils.isNotBlank(searchParam.getSearchWords())) {BoolQueryBuilder mutiShould = QueryBuilders.boolQuery();for(String column : searchType.getSearchColumn()) {mutiShould.should(QueryBuilders.termQuery(column+KEYWORD, searchParam.getSearchWords().trim()));}queryBuilder.must().add(mutiShould);}// 科室编码过滤if(StringUtils.isNotBlank(searchParam.getDeptNo())) {queryBuilder.must(QueryBuilders.termQuery("admissward"+KEYWORD, searchParam.getDeptNo().trim()));}/*** 有时间范围*/if(searchParam.getTimeType() > 0 && searchParam.getTimeType() < 3) {Date startDate = searchParam.getStartDate();Date endDate = searchParam.getEndDate();RangeQueryBuilder rangeBuilder = null;// 入院日期if(searchParam.getTimeType() == 1) {if(null != startDate) {rangeBuilder = QueryBuilders.rangeQuery("admissdate").gte(startDate.getTime());}if(null != endDate) {if(null == rangeBuilder) {rangeBuilder = QueryBuilders.rangeQuery("admissdate").lte(endDate.getTime());} else {rangeBuilder.lte(endDate.getTime());}}// 出院日期} else if(searchParam.getTimeType() == 2) {if(null != startDate) {rangeBuilder = QueryBuilders.rangeQuery("disdate").gte(startDate.getTime());}if(null != endDate) {if(null == rangeBuilder) {rangeBuilder = QueryBuilders.rangeQuery("disdate").lte(endDate.getTime());} else {rangeBuilder.lte(endDate.getTime());}}}if(null != rangeBuilder) {queryBuilder.must().add(rangeBuilder);}}SearchRequestBuilder searchBuilder = client.prepareSearch(searchType.getIndexType().get_index()).setTypes(searchType.getIndexType().get_type()).setSearchType(SearchType.DFS_QUERY_THEN_FETCH).setQuery(queryBuilder) .addSort(StringUtils.isBlank(searchType.getSortColumn())?SCORE:searchType.getSortColumn(), searchType.getOrder()==null?SortOrder.DESC:searchType.getOrder()).setFrom(pager.getStartRow()).setSize(pager.getPageSize()).setExplain(true);SearchResponse response = searchBuilder.execute().actionGet();long end = System.currentTimeMillis();logger.info("searchMutiField request indexType:{},searchparam:{},orderColumn:{},orderBy:{}.total hits:{},cost 【{}】 ms",searchType.getIndexType().get_type(),queryBuilder.toString(),searchType.getSearchColumn(),searchType.getOrder(),response.getHits().totalHits,(end-start));

上面的稍微复杂一点,是我生产环境的部分代码,对应的SQL语句是,其实你看到这一个例子应该就大概知道了怎样用SQL转化为代码,BoolQueryBuilder.must就相当于SQL里面的 AND 的概念,Should就是OR

select * from table_name where (column1='searchwords' or column2='searchwords' .. )and admissward='123456' and admissdate > '1412000212112' and admissdate < '141976521211' limit 10--我的判断逻辑是如果是入院日期查询就 admissdate > startdate and admissdate < endate--如果是出院日期 就disdate > startdate and disdate < enddate--这个逻辑我就不分开写出来了,省略了

二、使用ES注意事项

  • 默认的java.util.Date放到map,然后去创建索引,ES中会保存UTC时间格式,这个比较恶心!当然,时间格式你可以getTime之后当做long去存储,就是不够直观,也可以通过我上一篇文章中一样在创建索引的时候指定date类型字段的format属性。为了方便创建索引,我直接创建了一个xml配置文件来指定数据创建索引时固定其类型! 解析xml我就不贴了,要不然篇幅太长!

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapping SYSTEM "elastic-config.dtd">
    <!-- 属性参考 https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-store.html -->
    <mapping  ><!--  <datasource id="dataSource1" ref="springDataSource"></datasource>-->   <datasource id="dataSource" ><username>admin</username><password>admin</password><jdbcurl>jdbc:mysql://127.0.0.1:3306/message?useUnicode=true&amp;characterEncoding=UTF-8&amp;zeroDateTimeBehavior=round&amp;useCursorFetch=true&amp;verifyServerCertificate=false&amp;useSSL=false</jdbcurl><driver>com.mysql.jdbc.Driver</driver></datasource><sql-mappings><sql-mapping data-source-id="dataSource"><!-- 全量索引 构建 每周星期天3点执行 --><full-sql> <sql>SELECT * FROM HAHA ORDER BY ID ASC</sql><expression>0 0 3 ? * SUN</expression></full-sql><!-- 每日增量索引构建 --><incr-sql> <sql>SELECT * FROM HAHA WHERE GMT_CREATE > DATE_ADD(NOW(),INTERVAL -2 DAY) ORDER BY ID ASC</sql><expression>0 0 2 * * ?</expression></incr-sql><search-info><index>test</index><type>test</type><columns><column index-column="idindex" data-type="integer"sql-column="id" index="not_analyzed" store="no"  /><column index-column="nameindex" data-type="string"sql-column="name" index="not_analyzed" store="no" /><column index-column="blobtindex" data-type="byte"sql-column="blobt" index="not_analyzed" store="no" /> <column index-column="datesindex" data-type="date"sql-column="ttt" store="no" format="yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"locale="CHINA" />    <column index-column="tinytestindex" data-type="boolean"sql-column="tinytest" index="not_analyzed" store="no" /><column index-column="moneysindex" data-type="string"sql-column="moneys" index="not_analyzed" store="no" /><column index-column="ggggindex" data-type="date"sql-column="gggg" format="yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"store="no" />                                            </columns></search-info></sql-mapping></sql-mappings>
    </mapping>
  • 通过接口查出的时间格式是UTC格式,使用代码转换一下即可
    SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
    formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
    SimpleDateFormat standard = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    try {return standard.format(formatter.parse(admiss_time));
    } catch (ParseException e) {return null;
    }
  • 查询需要根据时间来查询怎么办?您不需要怎么办,不要你减去8小时再格式化
    //我们只需要获取当前我们本地时间之后getTime传入即可 admissdate >= xxxxx
    QueryBuilders.rangeQuery("admissdate").gte(startDate.getTime());
  • 频繁更新的数据的索引ID,可以尽量不使用UUID偷懒 。一个是速度快,另外如果使用我们自已的业务ID来当做索引的ID在更新的时候会很方便,你直接保存进去就会自动更新数据,而不是说新插一条数据,比如下面,分两次保存只会有一条数据存在索引,因为id是一样的!
    Map<String,Object> map = new HashMap<String,Object>();
    map.put("id", 1);
    //map.put('test',456);
    map.put("test", 1);
    //map.put('hehe',567);
    map.put("hehe", 2);
    IndexResponse response = client.prepareIndex("emr_document2", "user_info2",map.get('id').toString()).setSource(map).get();
  • 使用ES来做日志管控。官方有kibana+logstash+ES的日志管理解决方案,我们自己如果不想搞那么复杂引入那么多产品进来的话,可以直接自己用RandomAccessFile方式来读取日志文件后写入ES索引,像日志这种东西比较适合每日或者每周做一个单独饿索引,如:index = log_index_20170906 这种,好处不用说了吧,我们磁盘空间是有限的,如果把所有日志写到一个索引里面去,我们要清理历史不用的日志就麻烦一点,还不如每天一个索引,然后过期后就把历史没用的哪个索引直接删掉。

最后

  • 我为什么使用ES?

我单位乙方提供的数据库没有做比较好的分表方案,历史数据出院一个星期就转入B表,导致很多系统无法正常调用出院患者的病历数据和病人主索引信息,现在已经引入了搜索之后,正常提供全部患者主索引信息查询服务,用起来很爽!病历数据+患者主索引数据 总共不超过500W,查询速度相当快,都在20ms以下!

  • 后面我可以拿ES做什么?
  1. 病历全文检索,根据关键字来搜病历(这个大家都了解)。
  2. 病历归类,提供病历内容关键字归类之后,提取一个患者的病历连带出与之相同诊断或者病症的患者信息及用药方案,提供临床决策支持。
  3. 全院系统日志整合监控,这个很有必要,现在我们大大小小系统几十个,每个系统每天都可能出现各种问题,如果能试试把日志搜集过来,做个监控报警,日子会舒服很多。
  4. 我可以拿来吹牛逼(很重要!)哈哈,开个玩笑!其实说到底,我只是时间多一点,想学点东西,不让自己成为一个体制内的废人! 有时候一个人在这里做技术有一点小小的孤独感和伤感。

转载于:https://my.oschina.net/u/2461727/blog/1530245

Elasticsearch 5.5 SQL语句转Java Client 及相关注意事项(三)相关推荐

  1. mysql语句生成在线_在线数据库表(sql语句)生成java实体类工具

    相信每个做java开发的读者,都接触过SQL建表语句,尤其是在项目开发初期,因为数据库是项目的基石. 在现代项目开发中,出现了许多ORM框架,通过简单的实体映射,即可实现与数据库的交互,然而我们最初设 ...

  2. 【Elasticsearch】Elasticsearch如何实现 SQL语句中 Group By 和 Limit 的功能

    1.概述 转载:https://elasticsearch.cn/article/629 有 SQL 背景的同学在学习 Elasticsearch 时,面对一个查询需求,不由自主地会先思考如何用 SQ ...

  3. sql语句和java的关系_java中Statement 与 PreparedStatement接口之间的关系和区别

    Statement 和 PreparedStatement之间的关系和区别. 关系:PreparedStatement继承自Statement,都是接口 区别:PreparedStatement可以使 ...

  4. 【Spring Boot+Thymeleaf+MyBatis+mysql】实现电子商务平台实战(附源码)持续更新~~ 包括sql语句、java、html代码

    源码请点赞关注收藏后评论区留言和私信博主 开发环境:Web服务器使用Servlet容器,数据库采用mysql,集成开发环境为Spring Tool Suite(STS) 一.系统设计 电子商务平台分为 ...

  5. Elasticsearch 实现类似SQL语句中like %关键字% 的单纯模糊查询(不进行分词)

    一.前言 1.1 需求描述 用Elasticsearch 实现类似SQL中like的功能('%aaa%'),查询数据时,要前后模糊匹配,不要分词(用户输入AAA,检索的结果中AAA需要连在一起,不能是 ...

  6. 初学者应该了解的一些SQL语句及hr 用户解锁相关

    初学者应该了解的一些SQL语句 1.显示当前连接用户 SQL> show user: 2.查看系统拥有哪些用户 SQL> select * from all_users; 3.连接到新用户 ...

  7. 基础sql语句大全(详细解析,注意事项)

    1. 数据库及表操作 注意:如果需要本文的数据库文件,请下载,否则自己建表练习 sql文件 1.1. 创建.删除.查看数据库 1.1.1. 查看mysql服务器中所有数据库 SHOW DATABASE ...

  8. java中sql语句怎么把开始和结束时间作为参数写sql查询_JDBC数据库连接怎么操作?...

    之前一直听说过JDBC,但从来不知道它是何物的小伙伴们看过来啦! 一.概述 JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java A ...

  9. java中写sql语句的小小细节

    来源于:http://www.cnblogs.com/reine98/p/6180472.html 看如下一条sql语句 1 2 3 4 5 6 String sql="SELECT * F ...

最新文章

  1. 某网友认为程序员来钱太快!动不动就百万年薪!国内多数人工作一辈子也拿不到百万年薪!程序员:别总盯着行业头部少数人!...
  2. OSChina 周三乱弹 —— 孤独到都和病毒发生了感情了
  3. bzoj2194: 快速傅立叶之二
  4. 经典最短路算法的原理启示
  5. python添加音乐_python给视频添加背景音乐并改变音量的具体方法
  6. 图形学中画正方形的几种方式
  7. 软件下载页面php,PHP网页制作软件下载
  8. 【SSL】2021-08-19 1100.神秘数列
  9. 《人月神话》,没有银弹
  10. 夏季旅游度假照片展示短视频AE模板
  11. 苹果可以访问linux的smb,Samba For iOS让iPhone使用网上邻居使用体验教程
  12. Java 7从入门到精通 前 言
  13. 带你学开源项目:RxLifecycle-当Activity被destory时自动暂停网络请求
  14. ArcGIS按像元栅格值提取栅格
  15. 论文笔记之Non-Local
  16. 分析Adobe Illustrator CC(AI)中的橡皮擦和直线工具
  17. 中国汽车流通协会:2018年7月二手车市场分析
  18. ARM Linux中断机制分析
  19. 2017ife_yaoyao学院_task1
  20. arm汇编指令详细整理及实例详解

热门文章

  1. A2F-轻量级SISR网络 | Lightweight Single-Image Super-Resolution Network with Attentive Auxiliary Feature
  2. Dual Regression Networks for SISR 环境搭建 | 2020Paper | 【❤️Pytorch 实现❤️】
  3. avatar-view
  4. mysql字段掩码_access字段输入掩码之字符篇
  5. 华为便携机修改服务器密码,华为随身WiFi如何修改WiFi密码 华为随身WiFi修改WiFi密码方法【介绍】...
  6. 红米note5刷android,红米note5刷魔趣Android10上手体验!这速度,我爱了!
  7. java rgb十六进制数据转图片
  8. unityAndroid9.0不能下载AB包的问题
  9. 无线网络技术教程(第3版)--原理、应用与实验 金光江光亮 编著 复习资料 聊城大学考试题目
  10. 京东商品及评论 数据采集