文档章节

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

卡尔码农
 卡尔码农
发布于 2017/09/06 20:01
字数 1937
阅读 93
收藏 2
点赞 2
评论 0

前言

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

     1. Elasticsearch 5.5 入门必会(一)

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

 

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

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

         我们先看个简单的代码:

	@Test
	public 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使用,短语精准匹配
	 */
	@Test
	public 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%'

 

  • 聚合查询
@Test
	public 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. 我可以拿来吹牛逼(很重要!)哈哈,开个玩笑!其实说到底,我只是时间多一点,想学点东西,不让自己成为一个体制内的废人! 有时候一个人在这里做技术有一点小小的孤独感和伤感。

© 著作权归作者所有

共有 人打赏支持
卡尔码农
粉丝 89
博文 14
码字总数 18165
作品 0
常德
其他
Centos6搭建elk系统,监控IIS日志

**所需程序: 服务器端:java、elasticsearch、kikbana 客 户 端:IIS、logstash** 一、服务器端(192.168.10.46)操作: 先建立一个ELK专门的目录: [root@Cent65 ~]mkdir /elk/ 上传到elk...

D杀手D
04/24
0
0
Elasticsearch入门实践

一. 系统环境 操作系统:CentOS release 6.8 (Final) ES版本:6.1.1 二. 安装 先确认安装了Java运行时环境: 解压ES压缩包: 三. 启动 1. 启动ES单节点 当然,对于在后台以守护进程模式运行的...

哲别0
06/06
0
0
玩转 Elasticsearch 的 SQL 功能

最近发布的 Elasticsearch 6.3 包含了大家期待已久的 SQL 特性,今天给大家介绍一下具体的使用方法。 首先看看接口的支持情况 目前支持的 SQL 只能进行数据的查询只读操作,不能进行数据的修...

Medcl
06/28
0
0
Grafana、elasticsearch、kafka、logstash和pinpoint结合

一、Grafana 1)下载安装 wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-4.2.0-1.x8664.rpm sudo yum localinstall grafana-4.2.0-1.x86_64.rpm 2)启动 serv......

半船水
2017/10/25
0
0
Elasitcsearch High Level Rest Client学习笔记(一)

文档地址:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/6.1/java-rest-high.html java doc地址: https://artifacts.elastic.co/javadoc/org/elasticsearch/client/el......

木子SMZ
07/12
0
0
bboss v5.0.6.8 发布,持久支持Elasticsearch SQL

bboss v5.0.6.8发布,持久层支持Elasticsearch SQL和Elasticsearch JDBC. v5.0.6.8功能改进 持久层支持支持Elasticsearch SQL,使用参考文档:玩转Elasticsearch SQL功能 解决持久层/elasti...

bboss
07/02
0
0
ELK 实验(二)安装Elastic Search 单节点

Linux 安装 java -version echo $JAVA_HOME 木有返回,环境没有设置好。。。 vi /etc/profile export JAVAHOME=/usr/java/jdk1.8.0162 export JREHOME=$JAVAHOME/jre export CLASSPATH=$JAV......

pcdog
04/15
0
0
ElasticSearch使用

安装之前,请参考https://github.com/richardwilly98/elasticsearch-river-mongodb根据你的MongoDB版本号决定需要的elasticsearch版本号和插件号。 1)安装ES 下载ElasticSearch_版本号.tar....

强子哥哥
2014/04/09
0
0
centos 7 安装 elasticsearch-6.2.4

安装ES mkdir /data/software/ tar xvf elasticsearch-6.2.4.tar.gz -C /data/software/ cd /data/software/ ln -sv elasticsearch-6.2.4/ elasticsearch 或者 rpm -ivh elasticsearch-6.2.4......

会说话的鱼
07/04
0
0
bboss elasticsearch V5.0.8.2 发布

The best Elasticsearch Highlevel Rest Client API-----bboss v5.0.8.2 发布。 主要功能特色 ElasticSearch兼容性:2.x,5.x,6.x,+ JDK兼容性: jdk 1.6+ Spring boot兼容性:1.x,2.x ORM和DSL......

bboss
07/06
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

SpringBoot | 第七章:过滤器、监听器、拦截器

前言 在实际开发过程中,经常会碰见一些比如系统启动初始化信息、统计在线人数、在线用户数、过滤敏高词汇、访问权限控制(URL级别)等业务需求。这些对于业务来说一般上是无关的,业务方是无需...

oKong
16分钟前
2
0
存储结构分四类:顺序存储、链接存储、索引存储 和 散列存储

存储结构分四类:顺序存储、链接存储、索引存储 和 散列存储 存储结构分四类:顺序存储、链接存储、索引存储 和 散列存储。 顺序结构和链接结构适用在内存结构中。 顺序表每个单元都是按物理...

DannyCoder
27分钟前
0
0
Firefox 61已经为Ubuntu 提供支持

最新和最好的Mozilla Firefox 61 “Quantum”网络浏览器已经为Ubuntu Linux操作系统的用户提供了支持,现在可以通过官方软件库进行更新。 Mozilla于2018年6月26日发布了Firefox 61版本,该版...

六库科技
53分钟前
0
0
Win10升级后执行系统封装(Sysprep)报错

开始封装 一年多以前开始给公司封装Win10系统,便于统一给公司电脑初始化携带各种软件的系统,致力于装完既可以开发的状态。那时候最新的版本是Win10 1703版本,自然就以他为母盘,然后结合V...

lyunweb
今天
39
0
php 性能优化

#什么情况下会遇到性能问题 PHP 语法使用的不恰当

to_be_better
今天
0
0
Jenkins 构建触发器操作详解

前言 跑自动化用例每次用手工点击jenkins出发自动化用例太麻烦了,我们希望能每天固定时间跑,这样就不用管了,坐等收测试报告结果就行。 一、定时构建语法 * * * * * (五颗星,中间用空格隔...

覃光林
今天
0
0
IDEA配置技巧

超详细设置Idea类注释模板和方法注释模板 idea去掉注解param下划线 JetBrains全系列破解

AK灬
今天
0
0
rsync通过服务同步/Linux系统日志/screen工具

rsync通过服务同步 分为服务端(机器A) 和客户端(机器B) 机器A操作编辑/etc/rsyncd.conf配置文件 [root@yolks1 ~]# vim /etc/rsyncd.conf 文件中添加以下配置 port=873 ...

Hi_Yolks
今天
0
0
分发系统介绍expect脚本远程登录expect脚本远程执行命令 expect脚本传递参数

分发系统介绍 分发系统-expect讲解(也就是一个分发的脚本) 场景: 业务越来越大,网站app,后端,编程语言是php,所以就需要配置lamp或者lnmp,最好还需要吧代码上传到服务器上;但是因为业...

lyy549745
今天
0
0
android studio 中设置创建类时的说明信息(包含 作者 ,创建时间,注释说明等)

今天简单来说一下android studio开发工具中的 一个小设置功能; 在开发过程中我们习惯给新建的类添加一些注释信息,创建日期、时间和作者等。 设置信息 File—>Settings—>Editor—>File and...

切切歆语
今天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部