[TOC] 我们知道ElasticSearch提供的功能是相当多且复杂的,学习曲线陡峭。对于没有接触过Elastic的技术同学来说,学习周期和难度是较大的,而我们只需要满足最基本的查询就OK啦,没必要整那些没用的。千呼万唤始出来,在ElasticSearch6.3.0版本开始,在广大ES粉丝的强烈要求下,Elastic终于支持SQL查询了。虽然SQL查询功能很弱,但聊胜于无。SQL查询功能的提供,极大的方便了Elastic用户。因为不懂SQL的程序员,绝对不能算一个合格的程序员。如果您承认您是一个程序员,我相信你肯定熟悉SQL语句,至少select语句是没有问题的。所以该功能的提供对应Elastic的推广和运用会起到非常积极的作用。 下面,我们演示一下怎么来使用该通用模板的“执行SQL语句”接入点。在举例之前,您可以先了解一下elastic的SQL官方文档: https://www.elastic.co/guide/en/elasticsearch/reference/current/xpack-sql.html 紧接着2.5中的数据,我们写一个查询语句,需要满足以下要求:查询年纪不小于22岁(已经走上社会的人),姓王的,爱好音乐(sing、music、piano)的人。满足这个要求的SQL语句怎么写呢?大家一起来看一下如下的语句: ```sql select * from common_index where name like '%王%' and age>=22 and (hobbies like '%sing%' or hobbies like '%music%' or hobbies like '%piano%' ) order by age desc ``` 根据以上SQL,java的操作代码: ```java String sql = "select * from common_index where name like '%王%' and age>=22 " + "and (hobbies like '%sing%' or hobbies like '%music%' or hobbies like '%piano%' ) " + "order by age desc"; String res=new ShowApiRequest("http://route.showapi.com/2161-5","my_appId","my_appSecret") .addTextPara("sql",sql) .post(); System.out.println(res); ``` 返回的结果: ```css { "showapi_res_error": "", "showapi_res_code": 0, "showapi_res_id": "3490bcf174624ab78fdd4aaa957e69f6", "showapi_res_body": { "ret_code": 0, "remark": "操作已执行,结果请参考返回信息。", "columns": [ { "name": "age", "type": "long" }, { "name": "hobbies", "type": "text" }, { "name": "id_card", "type": "text" }, { "name": "name", "type": "text" } ], "rows": [ [ 28, "football piano Kongfu", null, "王五" ] ] } } ``` 我还以为返回的结果会是"隔壁老王"了,回看了下原始记录,原来他不懂音乐(^_^)! 在我们返回的记录中,发现有个为null数据,是因为有个字段id_card被用来作为_id使用了,也就是说id_card已经作为了整条记录的唯一标识,在这条记录中已经把id_card数据移除了,但字段还在,所以此处才出现了null的数据。注意观察columns信息中有id_card的信息。 重要的事情差点忘记说明了,select语句的格式: select [columns | *] from [index_name] where [column] [like / = / <> / > ...] value order by [column] [asc | desc] 以上事例演示的是一条完整的sql语句查询,如果还有附带条件,那就只能使用一段Json结构的语句来操作了,比如查询年龄大于20岁,每次最多返回2条数据,并且支持分页查询。 elastic原始的操作方式: POST /_sql?format=json ```css { "query": "SELECT name,age,hobbies FROM common_index where age>20 ORDER BY age DESC", "fetch_size": 2, "columnar": true } ``` 我们的接口操作的方式(java代码): ```java String sql = "{" + " \"query\": \"SELECT name,age,hobbies FROM common_index where age>20 ORDER BY age DESC\",\n" + " \"fetch_size\": 2,\n" + " \"columnar\": true\n" + "}"; String res=new ShowApiRequest("http://route.showapi.com/2161-5","my_appId","my_appSecret") .addTextPara("sql",sql) .post(); System.out.println(res); ``` 接口返回的数据: ```css { "showapi_res_error": "", "showapi_res_code": 0, "showapi_res_id": "19d219e950f84a74899e8efaa7269a29", "showapi_res_body": { "ret_code": 0, "values": [ [ "隔壁老王", "王五" ], [ 36, 28 ], [ "football book calligraphy chess stocks", "football piano Kongfu" ] ], "cursor": "q9qtAwFaAXNARFhGMVpYSjVRVzVrUm1WMFkyZ0JBQUFBQUFBQUFFZ1diVFE1ZFV4RGRVbFJXR2xOY0hKamNucHZjRWRSUVE9Pf////8PAwFmBG5hbWUBBG5hbWUBBHRleHQAAAABZgNhZ2UBA2FnZQEEbG9uZwAAAAFmB2hvYmJpZXMBB2hvYmJpZXMBBHRleHQAAAABBw==", "remark": "操作已执行,结果请参考返回信息。", "columns": [ { "name": "name", "type": "text" }, { "name": "age", "type": "long" }, { "name": "hobbies", "type": "text" } ] } } ``` 既然是分页查询,那第二次查询就需要用到cursor参数了: ```css POST /_sql?format=json {"cursor": "q9qtAwFaAXNARFhGMVpYSjVRVzVrUm1WMFkyZ0JBQUFBQUFBQUFFZ1diVFE1ZFV4RGRVbFJXR2xOY0hKamNucHZjRWRSUVE9Pf////8PAwFmBG5hbWUBBG5hbWUBBHRleHQAAAABZgNhZ2UBA2FnZQEEbG9uZwAAAAFmB2hvYmJpZXMBB2hvYmJpZXMBBHRleHQAAAABBw==", "columnar": true } ``` 注意:cursor值是有时效性的,默认时间是1分钟.也就是说超过1分钟后cursor值就失效了. 通过接口,执行以上sql的返回值: ```css { "showapi_res_error": "", "showapi_res_code": 0, "showapi_res_id": "d89533ff40fd4a1b878133fbe090a4fb", "showapi_res_body": { "ret_code": 0, "values": [ [ "张三", "李四" ], [ 23, 21 ], [ "football book", "art music football" ] ], "cursor": "q9qtAwFaAXNARFhGMVpYSjVRVzVrUm1WMFkyZ0JBQUFBQUFBQUFFa1diVFE1ZFV4RGRVbFJXR2xOY0hKamNucHZjRWRSUVE9Pf////8PAwFmBG5hbWUBBG5hbWUBBHRleHQAAAABZgNhZ2UBA2FnZQEEbG9uZwAAAAFmB2hvYmJpZXMBB2hvYmJpZXMBBHRleHQAAAABBw==", "remark": "操作已执行,结果请参考返回信息。" } } ```