Selector是MOQL提供的最核心的功能,它相当于SQL(结构化查询语言)中DQL(数据查询语言)的功能,即我们通常所说的Select关键字所描述的查询功能。它能够对Java内存中的对象数据进行查询、统计以及集合(如:UNION)操作。它可用于对持续不断产生的数据进行实时统计。即预先设定好统计条件,然后每当有数据产生就将其交给Selector进行统计分析。Selector会累计统计这些不断产生的数据,直到使用者取出统计结果将其持久化,并重置Selector让它进行后续的实时数据统计分析。这种模式可应用于分析模式固定的应用,可有效减少大数据统计分析的数据量,使其统计分析建立在初步统计分析结果的基础上。如:
//产生一个BeanA对象的链表,链表长度为100,对这100个BeanA对象进行统计分析 List<BeanA> beanAList = BeanFactory.createBeanAList(0,100); DataSetMap dataSetMap = new DataSetMapImpl(); dataSetMap.putDataSet("BeanA", beanAList); String sql = "select count(a.id) cnt, sum(a.num) sum, a.num%500 mod from BeanA a group by 3 having mod > 10 order by 1"; try { Selector selector = MoqlUtils.createSelector(sql); //对第一组数据进行统计分析 selector.select(dataSetMap); RecordSet recordSet = selector.getRecordSet(); outputRecordSet(recordSet); //累计对第二组数据进行统计分析 selector.select(dataSetMap); recordSet = selector.getRecordSet(); outputRecordSet(recordSet); //重置selector,以前的统计结果被清空 selector.reset(); //对第三组数据进行统计分析 selector.select(dataSetMap); recordSet = selector.getRecordSet(); outputRecordSet(recordSet); } catch (MoqlException e) { e.printStackTrace(); } |
Selector支持的语法结构与SQL相似,但与SQL不同的是,Selector是大小写敏感的,其语法中所有的关键字都是小写的。语法结构如下:
select [cache(N[,fifo|filo|lru|lfu])] [all|distinct]]SELECT_LIST fromTABLE_LIST [[inner|left|right|full]join]TABLE [[as]ALIAS] [,...] [onSEARCH_CONDITION] [...]] [whereSEARCH_CONDITION] [group byGROUP_BY_EXPRESSION] [havingSEARCH_CONDITION] [union [all]|except|symexcept|complementation|intersect[all]QUERY_EXPRESSION] [order byORDER_ITEM [asc |desc] [, ...]] [limit [OFFSET,]N[%]] [decorate by DECORATE_FUNCTION[, ...]] |
语法结构中的蓝色字体为Selector的关键字;用’[]’括起来的部分为可选的语法部分;大写斜体部分为可变填充部分,其中有些可变填充部分如SEARCH_CONDITION中也包括了Selector的关键字,将在下面Selector语法的子句中进行详细阐述。
定义了查询结果需要返回的字段、常量以及表达式。语法如下:
select [cache(N[,fifo|filo|lru|lfu])] [all|distinct]]COLUMN [[as]ALIAS] [,...]from . . . |
cache(N[,fifo|filo|lru|lfu])
查询运算可用的内存缓存区的大小。N为正整数,表示可以缓存的记录的条数。缓存的大小以可以缓存的记录条数来设定。该语法与传统SQL语法不同,因为MOQL是一种基于内存运算与统计分析的语法,所有的数据都缓存在内存中。若需要统计分析的数据是一个实时的,不断产生的数据,若不对缓存进行设定,则该统计很有可能会耗尽所有的内存。因此必须根据实际应用对查询可用的内存加以限定。但限定也会带来一个问题,就是它会带来数据的统计误差,但该误差相对其能带来的实时统计效果以及数据持久化空间的减少是可以接受的。fifo(先入先出)、filo(先入后出)、lru(最近最少使用)以及lfu(最不经常使用)是当缓存区满时的缓存区数据淘的汰算法,淘汰后产生的数据空间以放入新的数据。fifo是先入先出算法,即先存入缓存区的数据,在缓存区满时被率先淘汰并释放缓存空间;filo是先入后出算法,即先入缓存区的数据最后被淘汰;lru是最近最少使用算法,即淘汰最近最少使用的数据,即最不活跃的数据。在做top排名查询时,最不活跃的数据往往也不能排列到数据的最前面;lfu是最不经常使用算法,即被访问次数最少的数据。统计查询时,访问次数少往往也意味着统计值结果比较小。做数据排名时,也往往意味着该值不会被排列到前面。淘汰这些数据对最终结果不会有太大影响。如:
selectcache(10000) a.idid, sum(a.num)sum from DataStream a group by a.idorder by sumlimit 100 |
DataStream是一个不断产生数据的数据流,定期总有数据产生。我们需要统计它所产生的数据的相同id的数据和最大的前100名。由于DataStream总不断产生数据,我们没有办法缓存其产生的所有的数据,而持久化这些数据也意义不大。那么我们利用Selector定期对DataStream求统计值。每当计算完一次,就可以丢弃DataStream产生的数据,释放空间。由于DataStream产生的数据的id值理论上有无限大的可能,即使释放掉DataStream中的原始数据所占的空间,Selector的结果空间若不加限制,也仍可能导致内存溢出。因此必须通过设定cache值,来约束Selector的结果可以占用的最大空间限制。又由于该例中我们是选limit 100,为使其统计值相对误差更少一些,我们设其值为10000,即平均在100个值中获取一个有效结果,因缓存满,数据被淘汰导致的数据误差就会显的微不足道。
缺省情况下,cache的大小为100,缓冲区淘汰算法为fifo。当cache的值设为-1时,表示不对查询可用的缓存区的大小做限制。但使用该值时需要慎重,一个不合适的查询可能会导致整个虚拟机的内存溢出,从而影响系统的整体应用。
[all|distinct]
表示返回所有的查询结果数据还是将查询结果中的数据去重后再返回。数据去重时会判断是否有多条数据存在完全一致的情况,若多条数据完全一致,则返回且只返回一条数据。缺省为all,返回所有数据。而distinct表示只返回没有重复数据的结果。
COLUMN [[as]ALIAS] [,...]
表示查询要返回的结果数据列。COLUMN实际为一个Operand(详见:《MOQL—操作数(Operand)》),可以是常数、字段名、函数、表达式或者一个列筛选操作数(即SQL中的子查询)。ALIAS为COLUMN的别名,方便对COLUMN的记忆,起别名时可以选择使用或不使用”as”关键字。group by或order by子句可以通过COLUMN、ALIAS或者数据列所处位置的索引对数据列进行引用,索引值从1开始计数,详见group by子句和order by子句。
项目地址:http://sourceforge.net/projects/moql/
代码路径:svn://svn.code.sf.net/p/moql/code/trunk