cxyxiaokui / elasticsearch-sql-1

基于Java Rest High Level Client的Elasticsearch-Sql组件

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

基于Elasticsearch的Java Rest High Level Client的elasticsearch-sql查询组件

<dependency>
  <groupId>io.github.iamazy.elasticsearch.dsl</groupId>
  <artifactId>elasticsearch-sql</artifactId>
  <version>7.0.0.2</version>
</dependency>

插件(isql)

版本

elasticsearch version latest version remark isql version
6.x 6.6.0 6.6.0.1
6.x 6.6.1 6.6.1.1
6.x 6.6.2 6.6.2.1
6.x 6.7.0 6.7.0.1
6.x 6.7.1 6.7.1.1
7.x 7.0.0 7.0.0.2

安装

Elasticsearch {6.x,7.x}

./bin/elasticsearch-plugin install https://github.com/iamazy/elasticsearch-sql/releases/download/{isql-version}/elasticsearch-sql-plugin-{isql-version}.zip

使用

1. 使用sql语句直接查询elasticsearch里面的数据集
POST _isql
{
    "sql":"select * from fruit"
}
2. 将sql解析成elasticsearch的dsl
POST _isql/_explain
{
    "sql":"select * from fruit"
}

说明

目前使用文档无法及时更新出来,但是test目录中基本有所有的测试用例,可以结合生成的dsl和调试信息理解

CHANGELOG

2019-3-6:修复原版Nested类型的nested path识别错误的问题
2019-3-7:删除了大部分无用的代码,添加了geo_distance聚类方法
2019-3-25: 聚类使用递归实现添加多层嵌套聚类方式([>]表示嵌套聚类[,]表示同级聚类),具体用法见test目录
2019-3-26: 添加scroll id深度分页
2019-3-28: 更新nested功能,支持双层嵌套类型(再多就要考虑数据结构是否合理了)
2019-4-8: 添加高亮显示
2019-4-11: 添加Function Score
2019-4-24: 将elasticsearch-sql添加为elasticsearch插件 2019-4-28: 添加like not like 查询

CHANGELOG

版本

elasticsearch-sql es version
master 6.6.0
master 6.6.2
master 6.7.0
master 6.7.1
master 7.0.0

感谢

首先感谢elasticsearch-query-toolkit的作者gitchennan,elasticsearch-sql基于gitchennanelasticsearch-query-toolkit,并在其中稍作修改和添加部分功能,再次感谢gitchennan哈哈哈哈哈
gitchennan的github地址:elasticsearch-query-toolkit

介绍

elasticsearch-sql是一个基于sql查询的elasticsearch编程工具包,支持sql生成elasticsearch dsl,去掉了elasticsearch-query-toolkit中与Spring,Mybatis 集成的部分,有需要的话请参照elasticsearch-query-toolkit

特点

1)elasticsearch-sql是基于Java Rest High Level Client构建elasticsearch查询的,支持elasticsearch原生rest client调用以及第三方http请求
2)基于 alibaba的Druid数据连接池的SqlParser组件,解析sql速度快,自定义解析规则更方便
3)方便鉴权

抛弃elasticsearch传统的transport连接方式改用rest high level连接方式不仅仅是因为官方建议,而是在结合x-pack组件进行鉴权的时候更加方便 本人不知道在transport连接方式中如何复用transport client进行多用户的搜索请求 下面是官网的一段代码

import org.elasticsearch.xpack.client.PreBuiltXPackTransportClient;
...

TransportClient client = new PreBuiltXPackTransportClient(Settings.builder()
        .put("cluster.name", "myClusterName")
        .put("xpack.security.user", "transport_client_user:x-pack-test-password")
        ...
        .build())
    .addTransportAddress(new TransportAddress("localhost", 9300))
    .addTransportAddress(new TransportAddress("localhost", 9301));

每一个transport client都需要将用户名和密码写死在配置里面,如果要使用多用户进行请求的话,就不得不建立多个transport client连接,这种方式感觉很傻,尽管我之前写过用common-pool2组件管理transport client连接,但是一想到以后会有成千上万的用户访问就要建立成千上万的连接,想想都要爆炸💥
但是rest high level client就没有这个问题,它通过RequestOptions携带用户的token信息进行搜索请求,不同的用户搜索只需要分配不同的RequestOptions就行了

private static RequestOptions requestOptions(String token) {
        //设置允许返回的最大字节数
        HttpAsyncResponseConsumerFactory responseConsumerFactory = new HttpAsyncResponseConsumerFactory
                .HeapBufferedResponseConsumerFactory(Integer.MAX_VALUE);
        RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
        builder.setHttpAsyncResponseConsumerFactory(responseConsumerFactory);
        builder.addHeader("Authorization", "Basic " + token);
        return builder.build();
}

public Map<String, Object> get(String cluster,String index,String type, String id, String routing, String token) throws IOException {
        GetRequest getRequest = new GetRequest(index, type, id).routing(routing);
        GetResponse getResponse = getRestHighLevelClient(cluster).get(getRequest, requestOptions(token));
        return getResponse.getSourceAsMap();
}

简单又方便,简直不要太棒了好吧
🐷也许是我的使用问题,如果有人知道如何使用transport client进行多用户的搜索请求,麻烦告诉我一下,我还挺好奇的

功能点

我是向https://github.com/NLPchina/elasticsearch-sql的开发团队看齐的,功能点会慢慢的一点一点的添加的

elasticsearch-query-toolkit已有的功能

  • SQL Select

  • SQL Where

  • SQL Order by (Asc & Desc)

  • SQL Group by (Terms & Range)

  • SQL And & Or

  • SQL In

  • SQL Between And

  • SQL Is

  • SQL Not

  • SQL Null

  • SQL Nvl

  • SQL Max

  • SQL Min

  • SQL Sum

  • SQL Avg

  • SQL > & < & >= & <=

  • ES FullText

  • ES Match

  • ES MultiMatch

  • ES QueryString

  • ES SimpleQueryString

  • ES HasParent

  • ES HasChild

  • ES Join

  • ES Script

  • ES Fuzzy

  • ES Prefix

  • ES Regex

  • ES Term

  • ES Wildcard

  • ES Routing

  • ES Nested

  • ES Include[fields]

  • ES From

  • ES Size

  • ES Range(Number,Date)

elasticsearch-sql 新增的功能

  • ES MatchAll
  • ES MatchPhrase
  • ES MatchPhrasePrefix
  • ES DeleteByQuery
  • ES Cardinality (目前不支持Script的方式)
  • ES TopHits
  • ES Nested (elasticsearch-query-toolkit中nested表达方式不合理,已修正)
  • ES GeoDistance
  • 支持嵌套深层聚类
  • ES Scroll Id
  • ES 支持双层嵌套查询(nested(nested))现在以及以后也不会支持三层以上的嵌套查询
  • ES Highlighter
  • ES Boosting
  • ES Function Score
  • SQL Like

未来将要添加的功能

  • ES Highlighter
  • elasticsearch-sql[NLPChina]组件中我未添加的功能!!!

☀️未来的想法是将功能完善的跟NLPChina团队一样多嘻嘻

测试用例

提供几个SQL转DSL的例子(在源码test文件夹里),其他部分你们需要去elasticsearch-query-toolkit了解,或者自己看源码(推荐,原作者的代码很优秀)

1. Match

@Test
public void testParseFromMethodSource(){
   String sql="select * from fruits where match(name,'apple','prefix_length:21') and term(color,'red')";
   ElasticSql2DslParser sql2DslParser=new ElasticSql2DslParser();
   ElasticSqlParseResult parseResult = sql2DslParser.parse(sql,new String[]{"name","color"});
   System.out.println(parseResult.toPrettyDsl(parseResult.toRequest()));
}
{
  "from" : 0,
  "size" : 15,
  "query" : {
    "bool" : {
      "filter" : [ {
        "bool" : {
          "must" : [ {
            "match" : {
              "name" : {
                "query" : "apple",
                "operator" : "OR",
                "prefix_length" : 21,
                "max_expansions" : 50,
                "fuzzy_transpositions" : true,
                "lenient" : false,
                "zero_terms_query" : "NONE",
                "auto_generate_synonyms_phrase_query" : true,
                "boost" : 1.0
              }
            }
          }, {
            "term" : {
              "color" : {
                "value" : "red",
                "boost" : 1.0
              }
            }
          } ],
          "adjust_pure_negative" : true,
          "boost" : 1.0
        }
      } ],
      "adjust_pure_negative" : true,
      "boost" : 1.0
    }
  }
}

2. MatchPhrase,Term,Limit

@Test
public void testParseLimit(){
    String sql="select * from fruits where match_phrase(name,'apple') and term(color,'red') limit 2,9";
    ElasticSql2DslParser sql2DslParser=new ElasticSql2DslParser();
    ElasticSqlParseResult parseResult = sql2DslParser.parse(sql,new String[]{"name","color"});
    System.out.println(parseResult.toPrettyDsl(parseResult.toRequest()));
}
{
  "from" : 2,
  "size" : 9,
  "query" : {
    "bool" : {
      "filter" : [ {
        "bool" : {
          "must" : [ {
            "match_phrase" : {
              "name" : {
                "query" : "apple",
                "slop" : 0,
                "zero_terms_query" : "NONE",
                "boost" : 1.0
              }
            }
          }, {
            "term" : {
              "color" : {
                "value" : "red",
                "boost" : 1.0
              }
            }
          } ],
          "adjust_pure_negative" : true,
          "boost" : 1.0
        }
      } ],
      "adjust_pure_negative" : true,
      "boost" : 1.0
    }
  }
}

🐷Term(a,b) 也可以在SQL中直接写成a='b'

3)Terms Agg

@Test
public void testParseTermsAgg(){
    String sql="select * from fruits where name is not null and color is not null group by terms(weight,5000),terms(color,600)";
    ElasticSql2DslParser sql2DslParser=new ElasticSql2DslParser();
    ElasticSqlParseResult parseResult = sql2DslParser.parse(sql,new String[]{"name","color"});
    System.out.println(parseResult.toPrettyDsl(parseResult.toRequest()));
}
  "from" : 0,
  "size" : 15,
  "query" : {
    "bool" : {
      "filter" : [ {
        "bool" : {
          "must" : [ {
            "exists" : {
              "field" : "name",
              "boost" : 1.0
            }
          }, {
            "exists" : {
              "field" : "color",
              "boost" : 1.0
            }
          } ],
          "adjust_pure_negative" : true,
          "boost" : 1.0
        }
      } ],
      "adjust_pure_negative" : true,
      "boost" : 1.0
    }
  },
  "aggregations" : {
    "weight" : {
      "terms" : {
        "field" : "weight",
        "size" : 5000,
        "shard_size" : 10000,
        "min_doc_count" : 1,
        "shard_min_doc_count" : 1,
        "show_term_doc_count_error" : false,
        "order" : [ {
          "_count" : "desc"
        }, {
          "_key" : "asc"
        } ]
      }
    },
    "color" : {
      "terms" : {
        "field" : "color",
        "size" : 600,
        "shard_size" : 1200,
        "min_doc_count" : 1,
        "shard_min_doc_count" : 1,
        "show_term_doc_count_error" : false,
        "order" : [ {
          "_count" : "desc"
        }, {
          "_key" : "asc"
        } ]
      }
    }
  }
}

4. Delete

public static void main(String[] args) {
    String sql="DELETE from fruits where match_all() limit 1100";
    ElasticSql2DslParser elasticSql2DslParser=new ElasticSql2DslParser();
    ElasticSqlParseResult elasticSqlParseResult = elasticSql2DslParser.parse(sql, new String[]{"port"});
    System.out.println(elasticSqlParseResult.toPrettyDsl(elasticSqlParseResult.toDelRequest().getSearchRequest()));
}
{
  "size" : 1000,
  "query" : {
    "bool" : {
      "must" : [ {
        "match_all" : {
          "boost" : 1.0
        }
      } ],
      "adjust_pure_negative" : true,
      "boost" : 1.0
    }
  },
  "_source" : false
}

🐷 DSL里的size=1000和Java中的limit 1100含义不一样 size=1000 是DeleteByQueryRequest中的SearchRequest的Size,默认为1000 limit 1100 设置的是DeleteByQueryRequest的Size,只是在DSL中没有显示

5. Nested

为了表征nested path这个属性,采用 $ 符号指明
nested path必须以 $为nested类型的属性之前结尾(非常重要)
🐖:一个嵌套表达式最多包含2个$符号

重要:productapple为例,applenested类型,则查询时的nested path应该为product.apple 以下两种写法均正确

product$apple.name

下面这几种写法错误

$product$apple.name
product.apple$name
$product.apple$name
$product$apple$name
product$apple$name

Nested结构参照

"product" : {
    "properties" : {
        "apple" : {
            "type" : "nested",
            "properties" : {
                "name" : {
                "type" : "text"
                },
                "price" : {
                "type" : "double"
                }
            }
        }
    }
}

🌹其余的请去test目录下找吧

欢迎大家提issue

About

基于Java Rest High Level Client的Elasticsearch-Sql组件


Languages

Language:Java 100.0%