链式数据分析引擎解析

122 阅读2分钟

链式数据分析引擎解析

原仓库:github.com/at0x7c00/lo…

我套了个UI:gitee.com/0X00000000/…

函数入口解析

  • 函数调用这里采用了链式写法。
  • 但是这个链式前面的都是初始化数据的,最后一步才真正执行!
  • 有些链式前面处理数据,接着后面在处理。

数据处理简单流程

/**
 *过滤数据
 *这里保存结果数据
 *key 如果没有group by的时候是空的
 *    有group by则为分组的key;如果分组key有转换则进行转化
 *注意这里的key只能一个
 */
Map<Object,List<Object>> mapping;
//过滤数据
if(conditionCheckOK(line)){
    Object key = null;
    if(!StringUtil.isEmpty(groupBy)){
        key = atts[groupByIndex];
        key = preProcess((String)key,groupByIndex);
    }
    List<Object> list = mapping.get(key);
    if(list == null){
        list = new ArrayList<Object>();
    }
    list.add(line);
    mapping.put(key, list);
}

数据如何过滤

  • 先过滤数据
  • 在取数、有函数转化的进行函数处理(select 1,avg(1) from a group 1)
  • 这个函数转换需要注意。举例:平均值(维护总数,和)-》最后得平均值
  • 因为式select内容所以这里识别支持的函数也是个难点
  • 有分组的按照分组存放数据
  • 排序是放在数据最后输出的
  • 最后说下这里的处理基本单线程的。
@Test
	public void testWhere()throws Exception{
        //设置了count这里 这是有函数的类似avg、max、min
		scaner.select("count(1)")
        //过滤器这里可以用个链式过滤来实现
				.where(Conditions.and(Conditions.contains("6", "service/ws/WsService?"),
						Conditions.eq("8", "200")))
                .orderBy(OrderBy.desc(1))
				.list();
		scaner.print();
	}

	@Test
	public void testMoreCondition()throws Exception{
		scaner.select("0,3,6,8")
                //格式化获取到的数据
                .processor(3, processor)
				.where(Conditions.or(Conditions.eq("8", "404"),Conditions.eq("8", "302")))
				.list();
		scaner.print();
	}

初始化查询字段的解析

  • 先切割
  • 判断是否有( ->有则对应一个函数 ->提取出来对应的列和函数名
  • 分组的列也初始化提取了
private List<SelectedProp> selectedProps = new ArrayList<SelectedProp>();
private void init() throws Exception{
		String indexStrs[] = selectedPropsStr.split(",");
		for(String indexStr : indexStrs){
			Integer index = null;
			String function = null;
			if(indexStr.contains("(")){
				try{
					indexStr = indexStr.replaceAll("\\(", " ");
					indexStr = indexStr.replaceAll("\\)", " ");
					function = indexStr.substring(0,indexStr.indexOf(" "));
					indexStr = indexStr.substring(indexStr.indexOf(" ")+1);
					indexStr = indexStr.trim();
					index = Integer.parseInt(indexStr);
					hasFunction = true;
				}catch(Exception e){
					throw new WrongFormatException("select pattern is invalid:" + selectedPropsStr + ",near '" + indexStr + "'");
				}
			}else{
				try{
					index = Integer.parseInt(indexStr);
				}catch(Exception e){
					throw new WrongFormatException("content select is invalid:" + selectedPropsStr+ ",near '" + indexStr + "'");
				}
			}
			if(index > maxIndex){
				maxIndex = index;
			}
			selectedProps.add(new SelectedProp(index,function));
		}
		try{
			if(!StringUtil.isEmpty(groupBy)){
				groupByIndex = Integer.parseInt(groupBy);
			}
		}catch(Exception e){
			throw new WrongFormatException("content select is invalid:" + selectedPropsStr+ ",near '" + groupBy + "'");
		}
	}

平均数的格式转换

  • 接口定义
public interface  FunctionExecutor {
	final static Logger log = Logger.getLogger(FunctionExecutor.class.getName());
	public boolean accumulation(String lineValue);
	public Double getResult();
	
}
  • 平均数是实现
  • 最后获取函数最终结果
public class AvgFunction implements FunctionExecutor{
	double total;
	int lineCount;
	@Override
	public boolean accumulation(String lineValue) {
		try{
			total+=Double.parseDouble(lineValue);
			lineCount++;
		}catch(Exception e){
			log.log(Level.SEVERE, "数据:"+lineValue, e);
		}
		return false;
	}

	@Override
	public Double getResult() {
		if(lineCount>0){
			return NumberUtil.round2Digit((total*1.0)/lineCount);
		}
		return 0d;
	}
}