Upgrade to Pro — share decks privately, control downloads, hide ads and more …

实现一种像google搜索一样方便的es查询api#黄琛(C.Wong)#ESCC#3

medcl
October 25, 2014

 实现一种像google搜索一样方便的es查询api#黄琛(C.Wong)#ESCC#3

es官方提供api查询接口是采用json风格的语法采用来组织的,可读性非常好,但是对于编写者来说则费时费力。因为json本身是一种面向机器设计的文档格式,严格的语法和标点要求不利于人类快速编写而不出语法错误。相比而言,风靡世界的google搜索框则已经被证明是最高效也最易于掌握的并且能够表达复杂语义的人机交互界面。
想像一下,语法"INDEX=twitter age>20 | SORT user DESC"即可查询符合名称为twitter索引的和字段age大于20条件的数据并查询结果按照user倒序排列是不是要比写一个json要愉快一些。同样的,"INDEX=twitter | STATS SUM(upflow) BY user"可以表达分组和统计功能。关键字AND、OR、DC、MIN、MAX、AVG、EVAL、TIMESPAN、LIMIT等可以添加到查询语句中以表达更加复杂的语义。

我们按照易用性的原则重新为es设计并实现了这种查询api,采用es rest插件方式,命名为elasticsearch-rest-command并开源在github上。同时,我们还设计了一个ui来支持快速查询和浏览。

下面我将详细说明是如何使用javacc来实现支持这种命令+管道风格的语法解析并查询得到对应结果。

medcl

October 25, 2014
Tweet

More Decks by medcl

Other Decks in Technology

Transcript

  1. elasticsearch的官方query dsl { "match" : { "message" : { "query"

    : "this is a test", "operator" : "and" } } }
  2. 这样的接口 •  search src="10.9.165.*" OR dst="10.9.165.8" •  search src="10.9.165.*" OR

    dst="10.9.165.8" | sort dst •  search src="10.9.165.*" OR dst="10.9.165.8" | sort dst | stats sum(bytes) as ASumOfBytes by clientip 搜索条件 处理命令 处理命令 管道符 管道符 search src="10.9.165.*" OR dst="10.9.165.8" sort dst stats sum(bytes) by client
  3. 支持的命令 •  search(2014-4-1) –  search <searchoptions> <BooleanExpression> –  logicalexpression:and/or/not/嵌套/default=and – 

    operator:[!]=/>[=]/<[=]/ –  searchoptions: sourcetype/index/hasparent/haschild •  sort (2014-4-21) –  ...| sort <field> [DESC/ASC] •  stats(2014-4-10) –  ... | stats [statsoptions] <StatsFunction> [ByClause] –  StatsFunction:count(..),sum(..),avg(..),max(..),min(..),dc(...) –  parameter:fieldname/eval(script) –  ByClause: By <parameterlist> –  statsoptions:minicount,limit,span,timespan •  join (2014-06-13) –  ... | join <fieldlist> ( subsearch ) –  eg:index=comment | join userid (search index=user) •  table(2014-06-16) –  ... | table <filedlist> –  filedlist支持通配符
  4. 主要调用流程 class CommandRestHandler extends BaseRestHandler{ void handleRequest(...){ commandString = request.param("q",

    ""); parser = new CommandParser(commandString); search = new Search(parser, client, logger); switch(mode){ case 0:result = search.executeQueryWithNonJoin(); case 1:result = search.executeQuery(); case 2:result = search.executeReport(); case 3:result = search.executeDownload(); case 4:result = search.executeDelete() } } }
  5. 如何表示嵌套的布尔表达式 SearchStatement::=<K_SEARCH> ( SearchOption )* ( BooleanExpression )? BooleanExpression::=AndExpression (

    <K_OR> AndExpression )* AndExpression::=UnaryExpression ( <K_AND> UnaryExpression )* UnaryExpression::=( <K_NOT> )? ( <O_LPAREN> BooleanExpression <O_RPAREN> | PredicateExpression ) PredicateExpression::=( ComparisonExpression ( ComparisonExpression | TermExpression )* | TermExpression ( ComparisonExpression | TermExpression )* ) TermExpression::=( ( <S_INTEGER> | <S_FLOAT> | <S_IDENTIFIER> ) | <S_QUOTED_STRING> ) ComparisonExpression::=<S_IDENTIFIER> ( <O_EQ> | <O_NEQ> | <O_GT> | <O_GTE> | <O_LT> | <O_LTE> ) ( ( <S_INTEGER> | <S_FLOAT> | <S_IDENTIFIER> ) | <S_QUOTED_STRING> )
  6. 递归遍历Abstract Syntax Tree得 到Query DSL QueryBuilder genQueryBuilder(SimpleNode tree){ switch(nodeType){ case

    JJT_OREXPR: return fb.or(genQueryBuilder(tree.children)); case JJT_ANDEXPR/JJT_PREDICATEEXPRESSION: return fb.must(genQueryBuilder(tree.children)); case JJT_UNARYEXPR: return fb.mustnot(genQueryBuilder(tree.children)); case JJT_COMPARISONEXPRESSION/JJT_TERMEXPRESSION: return QueryBuilders.termQuery/matchPhraseQuery /rangeQuery/prefixQuery/wildcardQuery; } }