Esper事件处理引擎_12_EPL 语法_5_Subqueries子查询

官方地址:http://www.espertech.com


Esper 事件引擎栏目:http://blog.csdn.net/xiaohulunb/article/category/2436609


EPL 语法代码见-GitHub代码地址:点击打开链接


涉及 Javabean,Listener,main 以 GitHub 包下为最新更,注释解释排版有问题可参考源码


Subqueries子查询语法

package com.framework_technology.esper.epl;

import com.framework_technology.esper.javabean.Apple;
import com.framework_technology.esper.javabean.Banana;
import com.framework_technology.esper.javabean.Yieldly;

/**
 * Subqueries子查询
 * <p>
 * 基本上与SQL 的写法类似。
 * <p>
 * API - 5.11. Subqueries
 *
 * @author wei.Li by 14-8-12.
 */
public class EPL_5_Subqueries {


    /**
     * 以下限制适用于子查询:
     * <p>
     * 1.子查询流定义必须定义一个数据窗口或其它视图,以限制子查询的结果,减少了保持子查询执行的事件数
     * 2.子查询只能从子句包含一个select子句,一个where子句和GROUP BY子句。 having子句,以及连接,外连接和输出速率限制在子查询中是不允许的。
     * 3.如果使用聚合函数在子查询时,请注意以下限制:
     * 3.1没有一个相关流(次)的性质可以在聚合函数中使用。
     * 3.2子选择流的特性都必须在聚合函数。
     *
     * @return epl[]
     */
    protected static String subqueries() {

        /**
         * 子查询结果作为外部事件的属性
         * Apple事件 的 id 与 当前窗口中的最后一个Banana 的price 作为结果集输出
         */
        String epl1 = "select id, (select price from " + Banana.CLASSNAME + ".std:lastevent()) as lastBanana_price from " + Apple.CLASSNAME;

        /**
         * 子查询关联外部事件的属性
         */
        String epl2 = "select * from " + Apple.CLASSNAME + " as Apple where 3 = " +
                "  (select price from " + Banana.CLASSNAME + ".std:unique(id) where id = Apple.id)";
        //每进入一个Apple 事件。查询 id 与当前窗口中Banana 按照std:unique(id)保留的所有唯一值,无一个匹配则输出 null
        String epl3 = "select id, (select price from " + Banana.CLASSNAME + ".std:unique(id) where id = apple.id) as price from " + Apple.CLASSNAME + " as apple";

        /**
         * 子查询内部事件作为外部事件的属性
         */
        String epl4 = "select (select * from " + Banana.CLASSNAME + ".std:lastevent()) as banana from " + Apple.CLASSNAME;

        /**
         * 子查询中应用聚合函数
         */
        String epl5 = "select * from " + Apple.CLASSNAME + " where price > (select max(price) from " + Banana.CLASSNAME + "(id='Banana_Id').std:lastevent())";
        return epl4;
    }


    /**
     * The 'exists' Keyword
     *
     * @return epl
     */
    protected static String exists() {
        String epl1 = "select * from " + Apple.CLASSNAME + " as RFID " +
                "  where exists (select * from " + Banana.CLASSNAME + ".std:unique(id) where id = RFID.id)";
        return epl1;
    }


    /**
     * The 'in' and 'not in' Keywords
     *
     * @return epl
     */
    protected static String in_notin() {
        String epl1 = "select * from " + Apple.CLASSNAME + " as RFID " +
                "  where RFID.id in (select id from " + Banana.CLASSNAME + ".std:unique(id))";
        return epl1;
    }


    /**
     * The 'any' and 'some' Keywords
     * any :至少大于结果集的一个 or 连接
     * some:至少等于结果集的一个 or 连接
     *
     * @return epl
     */
    protected static String any_some() {
        String epl1 = "select * from " + Apple.CLASSNAME + " as RFID " +
                "  where RFID.id < any(select id from " + Banana.CLASSNAME + ".win:keepall())";
        return epl1;
    }


    /**
     * The 'all' Keyword
     * all:必须小于所有结果集的值才满足 and 连接
     *
     * @return epl
     */
    protected static String all() {
        String epl1 = "select * from " + Apple.CLASSNAME + " as RFID " +
                "  where RFID.id < all(select id from " + Banana.CLASSNAME + ".win:keepall())";
        return epl1;
    }


    /**
     * EPL也同样支持join,并且包含了full outer join / left outer join / right outer join / inner join等。
     * 和sql基本无差别。
     *
     * @return epl
     */
    protected static String join() {
        /**
         * inner join
         在没有任何关键字的修饰下,即为默认join方式,也就是inner join。
         必须等到所有join的事件都到了才可能输出,因为要是有where关联两个事件,得满足where条件了才能输出
         如果只有Apple到或者Banana到都不会输出内容。std:lastevent是一种data window。如果不加特殊修饰的话(特殊修饰?下面会告诉你),
         事件必须有data window或者view修饰,否则会出现语法错误。
         当然,不同的事件可以用不同的data window修饰,并没有规定要一样。
         */
        String epl1 = "select * from " + Apple.CLASSNAME + ".std:lastevent(), " + Banana.CLASSNAME + ".std:lastevent()";

        /**
         * full outer join
         上面看到的默认join方式是要求所有join的事件都必须到达引擎才会输出,并且join的事件之间通过where子句设置了条件判断,
         还得到达的两个事件满足条件了才能输出,而full outer join正好解决了这个问题,不管哪个事件到达,不管是否符合条件,都会输出。

         输出结果有4种可能:
         a.当只有Apple事件到达,没有满足join条件,会输出Apple事件,且Banana事件为null。
         b.当只有Banana事件到达,没有满足join条件,会输出Banana事件,且Apple事件为null。
         c.当两个事件都到达了,且没有满足join条件,即price不相等,则a,b情况各出现一次。
         d.当两个事件都到达了,且满足join条件,即price相等,即可输出满足条件的事件。
         所以说不管什么情况下,当前进入的事件都会输出,至于join的那个事件,满足即输出事件,不满足即输出null。
         */
        String epl2 = "select * from " + Apple.CLASSNAME + ".std:lastevent() as o full outer join " + Banana.CLASSNAME + ".std:lastevent() as b on o.price = b.price";

        /**
         * left outer join
         full outer join输出了所进入的所有事件,不满足join条件的就输出null,
         而left outer join则规定关键字左边的事件可以即刻输出,而关键字右边的事件必须满足join条件才可输出。

         因为Apple事件在left outer join的左边,所以他的输出不受join条件的限制,即事件到来该怎么输出怎么输出。
         但是Banana就不同,由于有join条件限制,即两个事件的price要相等,所以如果Banana事件到达的时候,
         如果没有满足条件的Apple事件,则Banana事件是不会输出的。(注意:输出null也算输出,这里是null都不会输出,即不触发listener)
         */
        String epl3 = "select * from " + Apple.CLASSNAME + ".std:lastevent() as pi left outer join " + Banana.CLASSNAME + ".std:lastevent() as pe on pi.price = pe.price";

        /**
         * right outer join
         和left outer join相反,在关键字右边的事件不受join条件约束,而左边的事件必须满足join条件才可输出。具体例子我就不举了,大家可以写两个句子试试。

         此外,在使用以上4种join的时候,可以多种join混用。
         on后面的表达式是join的限制条件,且只能用“=”,如果想用其他操作符,则必须放到where子句中,这点尤其要注意。
         多个限制条件只能用and连接,不能用逗号,且限制的事件也要一样。
         */
        String epl4 = "select * from " + Yieldly.CLASSNAME + ".std:lastevent() as a " +
                "     left outer join " + Banana.CLASSNAME + ".std:lastevent() as b on a.price = b.price " +
                "     full outer join " + Apple.CLASSNAME + ".std:lastevent() as o on o.price = a.price";
        /**
         * // a,b分别是两个事件的别名

         // 正确写法
         ……on a.price = b.price and a.size = b.size……

         // 错误写法1:不能用逗号连接
         ……on a.price = b.price, a.size = b.size……

         // 错误写法2:必须针对同样的事件进行限制(c是另一个事件的别名)
         ……on a.price = b.price and a.size = c.size……

         */


        /**
         * Unidirectional Join
         之前说到,如果不加特殊修饰,则join的事件都需要data window或者view修饰,目的是为了暂存事件以便等待满足条件的事件并执行join。
         如果想让某个事件到来时直接触发join,不需要暂存,也就是不需要data window或者view修饰,则需要加上一个特殊关键字——unidirectional。

         epl5的意思是:维持最新的Banana事件,直到一个和Banana的price相等的Apple事件到来时输出两者。
         由于有unidirectional的修饰,表明Apple事件是即时触发join操作,也就是说进入此EPL的Apple事件是无状态的。
         所以当Apple事件到来时,如果没有price相等的Banana,则什么输出也没有,即使下一个Banana事件的price和之前来的Apple的price相等也不会有输出,
         因为那个Apple事件已经从这个句子的上下文中移除了。
         */
        String epl5 = "select * from " + Apple.CLASSNAME + " as a unidirectional, " + Banana.CLASSNAME + ".std:lastevent() as b where a.price = b.price";
        /**
         * unidirectional使用很简单,但是也有其限制:
         1.在一个join句子中,unidirectional关键字只能用于一个事件流。
         2.用unidirectional修饰的事件流,不能通过esper的查询api查出来,因为该事件流是无状态的,不会暂存在引擎中,所以就没法查了。(关于查询api,后面的章节会详说)
         3.使用了unidirectional修饰的事件流就不能再用data window或者view修饰了,也就是说他们是互斥的。
         */
        
        return epl5;
    }

}


你可能感兴趣的:(合并,批处理,Esper,espertech,事件引擎)