All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.scudata.dm.op.GroupsResult Maven / Gradle / Ivy

Go to download

SPL(Structured Process Language) A programming language specially for structured data computing.

There is a newer version: 20241126
Show newest version
package com.scudata.dm.op;

import com.scudata.array.IArray;
import com.scudata.common.MessageManager;
import com.scudata.common.ObjectCache;
import com.scudata.common.RQException;
import com.scudata.dm.BaseRecord;
import com.scudata.dm.ComputeStack;
import com.scudata.dm.Context;
import com.scudata.dm.Current;
import com.scudata.dm.DataStruct;
import com.scudata.dm.Env;
import com.scudata.dm.ListBase1;
import com.scudata.dm.Sequence;
import com.scudata.dm.Table;
import com.scudata.dm.cursor.ICursor;
import com.scudata.expression.Expression;
import com.scudata.expression.Gather;
import com.scudata.expression.Node;
import com.scudata.resources.EngineMessage;
import com.scudata.util.HashUtil;
import com.scudata.util.Variant;

/**
 * ???ڶ?????????????ִ?а????ֶν????ڴ???????????
 * @author RunQian
 *
 */
public class GroupsResult extends IGroupsResult {
	private Expression[] exps; // ???????ʽ
	private String []names; // ?????ֶ???
	private Expression []calcExps; // ͳ?Ʊ???ʽ
	private String []calcNames; // ͳ???ֶ???
	private String opt; // ????ѡ??
	private Context ctx; // ??????????
	
	private HashUtil hashUtil; // ?ṩ??ϣ????Ĺ?ϣ??
	private ListBase1 []groups; // ??ϣ??
	private Node[] gathers = null; // ͳ?Ʊ???ʽ?е?ͳ?ƺ???
	
	private DataStruct ds; // ????????ݽṹ
	private int keyCount; // ?????ֶ???
	private int valCount; // ?????ֶ???
	
	private Table result; // ??????ܽ??
	private BaseRecord prevRecord; // ??һ?????????¼
	
	private SortedGroupsLink link; // ????hѡ??
	
	private boolean oOpt;
	private boolean iOpt;
	private boolean nOpt;
	private boolean hOpt;
	public boolean XOpt;//ʹ?ö?̬?????Ż???????????ʹ??
	private boolean eOpt;

	/**
	 * ??ʼ??????
	 * @param exps		???????ʽ
	 * @param names		???????ʽ??
	 * @param calcExps	ͳ?Ʊ???ʽ
	 * @param calcNames	ͳ?Ʊ???ʽ??
	 * @param opt		????ѡ??
	 * @param ctx		?????ı???
	 */
	public GroupsResult(Expression[] exps, String[] names, Expression[] calcExps, 
			String[] calcNames, String opt, Context ctx) {
		this(exps, names, calcExps, calcNames, opt, ctx, Env.getDefaultHashCapacity());
	}
	
	/**
	 * ??ʼ??????
	 * @param exps		???????ʽ
	 * @param names		???????ʽ??
	 * @param calcExps	ͳ?Ʊ???ʽ
	 * @param calcNames	ͳ?Ʊ???ʽ??
	 * @param opt		????ѡ??
	 * @param ctx		?????ı???
	 * @param capacity	?????ϣ????С
	 */
	public GroupsResult(Expression[] exps, String[] names, Expression[] calcExps, 
			String[] calcNames, String opt, Context ctx, int capacity) {
		this.exps = exps;
		this.names = names;
		this.calcExps = calcExps;
		this.calcNames = calcNames;
		this.opt = opt;
		this.ctx = ctx;
		
		// ???ݱ???ʽ???֣????ɸ????е????֡??????????????ɽ?????ṹ
		// ???ɷ??????ʽ??Ӧ???е?????
		if (exps != null) {
			keyCount = exps.length;
		}

		// ????ͳ?Ʊ???ʽ??Ӧ???е?????, ȡ?þۺϺ???
		if (calcExps != null) {			
			gathers = Sequence.prepareGatherMethods(this.calcExps, ctx);
			valCount = gathers.length;
		}

		// ?ϲ???????????ͳ???????????ɽ??????????
		String[] colNames = new String[keyCount + valCount];
		if (names != null) {
			System.arraycopy(names, 0, colNames, 0, keyCount);
		}
		
		if (calcNames != null) {
			System.arraycopy(calcNames, 0, colNames, keyCount, valCount);
		}

		// ???ɽ???????ݽṹ
		ds = new DataStruct(colNames);
		ds.setPrimary(names);

		// ???ú???ѡ??????ݺ???ѡ??ж??Ƿ???Ҫ??ϣ??
		if (opt != null) {
			if (opt.indexOf('o') != -1) {
				oOpt = true;
			} else if (opt.indexOf('i') != -1) {
				iOpt = true;
				if (keyCount != 1) {
					MessageManager mm = EngineMessage.get();
					throw new RQException("groups" + mm.getMessage("function.invalidParam"));
				}
			} else if (opt.indexOf('n') != -1) {
				nOpt = true;
				if (keyCount != 1) {
					MessageManager mm = EngineMessage.get();
					throw new RQException("groups" + mm.getMessage("function.invalidParam"));
				}
			} else if (opt.indexOf('h') != -1) {
				if (keyCount > 0) {
					hOpt = true;
				}
			} else if (opt.indexOf('X') != -1) {
				XOpt = true;
			}
			
			if (valCount == 1 && opt.indexOf('e') != -1) eOpt = true;
		}
		
		if (hOpt) {
			link = new SortedGroupsLink();
		} else if (keyCount != 0 && !oOpt && !iOpt && !nOpt) {
			hashUtil = new HashUtil(capacity);
			groups = new ListBase1[hashUtil.getCapacity()];
		}
		
		result = new Table(ds, 1024);
	}
	
	/**
	 * ȡ????????ݽṹ
	 * @return DataStruct
	 */
	public DataStruct getResultDataStruct() {
		return ds;
	}
	
	/**
	 * ȡ???????ʽ
	 * @return ????ʽ????
	 */
	public Expression[] getExps() {
		return exps;
	}

	/**
	 * ȡ?????ֶ???
	 * @return ?ֶ???????
	 */
	public String[] getNames() {
		return names;
	}

	/**
	 * ȡ???ܱ???ʽ
	 * @return ????ʽ????
	 */
	public Expression[] getCalcExps() {
		return calcExps;
	}

	/**
	 * ȡ?????ֶ???
	 * @return ?ֶ???????
	 */
	public String[] getCalcNames() {
		return calcNames;
	}

	public ListBase1[] getGroups() {
		return groups;
	}

	public Node[] getGathers() {
		return gathers;
	}

	public DataStruct getDs() {
		return ds;
	}

	/**
	 * ȡ??????ܽ??
	 * @return Table
	 */
	public Table getResult() {
		return result;
	}
	
	/**
	 * ȡѡ??
	 * @return
	 */
	public String getOption() {
		return opt;
	}
	
	/**
	 * ȡ?Ƿ??????????
	 * @return true???ǣ????ݰ??????ֶ?????false??????
	 */
	public boolean isSortedGroup() {
		return oOpt;
	}
	
	/**
	 * ȡ???λ??ܱ???ʽ?????ڶ??̷߳???
	 * @return
	 */
	public Expression[] getRegatherExpressions() {
		if (valCount > 0) {
			Expression []valExps = new Expression[valCount];
			for (int i = 0, q = keyCount + 1; i < valCount; ++i, ++q) {
				Node gather = calcExps[i].getHome();
				gather.prepare(ctx);
				valExps[i] = gather.getRegatherExpression(q);
			}
			
			return valExps;
		} else {
			return null;
		}
	}
	
	/**
	 * ȡ???λ??????ݽṹ
	 * @return DataStruct
	 */
	public DataStruct getRegatherDataStruct() {
		return ds;
	}
	
	/**
	 * ȡ???λ??ܺ????ڼ??????ս???ı???ʽ??avg???ܱ??ֳ?sum??count???н??м???
	 * @return
	 */
	public Expression[] getResultExpressions() {
		return null;
	}
	
	/**
	 * ????????ʱ??ȡ??ÿ???̵߳??м????????????Ҫ???ж??λ???
	 * @return Table
	 */
	public Table getTempResult() {
		if (hashUtil != null) {
			this.hashUtil = null;
			this.groups = null;
		}  else if (nOpt) {
			result.deleteNullFieldRecord(0);
		} else if (hOpt) {
			if (opt == null || opt.indexOf('u') == -1) {
				result = link.toTable(ds);
			}

			link = null;
		}
		
		Table table = result;
		prevRecord = null;
		result = null;

		if (table.length() > 0) {
			if (valCount > 0) {
				table.finishGather1(gathers);
			}
			
			return table;
		} else {
			return null;
		}
	}

	/**
	 * ȡ??????ܽ??
	 * @return Table
	 */
	public Table getResultTable() {
		if (hashUtil != null) {	
			if (opt == null || opt.indexOf('u') == -1) {
				int []fields = new int[keyCount];
				for (int i = 0; i < keyCount; ++i) {
					fields[i] = i;
				}
	
				result.sortFields(fields);
			}
	
			this.hashUtil = null;
			this.groups = null;
		} else if (nOpt) {
			if (opt.indexOf('0') != -1) {
				result.deleteNullFieldRecord(0);
			} else {
				int len = result.length();
				IArray mems = result.getMems();
				for (int i = 1; i <= len; ++i) {
					BaseRecord r = (BaseRecord)mems.get(i);
					if (r.getNormalFieldValue(0) == null) {
						r.setNormalFieldValue(0, ObjectCache.getInteger(i));;
					}
				}				
			}
		} else if (hOpt) {
			if (opt == null || opt.indexOf('u') == -1) {
				result = link.toTable(ds);
			}

			link = null;
		}

		Table table = result;
		prevRecord = null;
		result = null;
		
		if (table.length() > 0) {
			if (valCount > 0) {
				table.finishGather(gathers);
			}
			
			if (!nOpt && opt != null && opt.indexOf('0') != -1) {
				table.deleteNullFieldRecord(0);
			}
			
			if (eOpt) {
				table = table.fieldValues(ds.getFieldCount() - 1).derive("o");
			}
			
			//table.trimToSize();
		} else if (opt == null || opt.indexOf('t') == -1) {
			table = null;
		}
		
		return table;
	}
	
	/**
	 * ???????ͽ???ʱ????
	 * @param ctx ??????????
	 */
	public void finish(Context ctx) {
	}
	
	 /**
	  * ???????ͽ?????ȡ???յļ?????
	  * @return
	  */
	public Object result() {
		return getResultTable();
	}
	
	/**
	 * ???????͹????????ݣ??ۻ??????յĽ????
	 * @param seq ????
	 * @param ctx ??????????
	 */
	public void push(Sequence table, Context ctx) {
		if (table == null || table.length() == 0) return;
		
		if (hashUtil != null) {
			addGroups(table, ctx);
		} else if (oOpt) {
			addGroups_o(table, ctx);
		} else if (iOpt) {
			addGroups_i(table, ctx);
		} else if (nOpt) {
			addGroups_n(table, ctx);
		} else if (hOpt) {
			addGroups_h(table, ctx);
		} else {
			addGroups_1(table, ctx);
		}
	}

	/**
	 * ???????͹??????α????ݣ??ۻ??????յĽ????
	 * @param cursor ?α?????
	 */
	public void push(ICursor cursor) {
		Context ctx = this.ctx;
		if (hashUtil != null) {
			while (true) {
				// ???α???ȡ??һ?????ݡ?
				Sequence src = cursor.fuzzyFetch(ICursor.FETCHCOUNT);
				if (src == null || src.length() == 0) break;
				
				// ?????????ӵ????????࣬??ִ??ͳ?ƺ?????
				addGroups(src, ctx);
			}
		} else if (oOpt) {
			while (true) {
				Sequence src = cursor.fuzzyFetch(ICursor.FETCHCOUNT);
				if (src == null || src.length() == 0) break;
				
				addGroups_o(src, ctx);
			}
		} else if (iOpt) {
			while (true) {
				Sequence src = cursor.fuzzyFetch(ICursor.FETCHCOUNT);
				if (src == null || src.length() == 0) break;
				
				addGroups_i(src, ctx);
			}
		} else if (nOpt) {
			while (true) {
				Sequence src = cursor.fuzzyFetch(ICursor.FETCHCOUNT);
				if (src == null || src.length() == 0) break;
				
				addGroups_n(src, ctx);
			}
		} else if (hOpt) {
			while (true) {
				Sequence src = cursor.fuzzyFetch(ICursor.FETCHCOUNT);
				if (src == null || src.length() == 0) break;
				
				addGroups_h(src, ctx);
			}
		} else {
			while (true) {
				Sequence src = cursor.fuzzyFetch(ICursor.FETCHCOUNT);
				if (src == null || src.length() == 0) break;
				
				addGroups_1(src, ctx);
			}
		}
	}
	
	/**
	 * ???????ݣ?ͬʱ???????ͳ?ƺ???
	 * 
	 * @param table	?????ӵ?????
	 */
	private void addGroups(Sequence table, Context ctx) {
		final int INIT_GROUPSIZE = HashUtil.getInitGroupSize(); // ??ϣ???Ĵ?С
		HashUtil hashUtil = this.hashUtil; // ??ϣ??????
		ListBase1 []groups = this.groups; // ??ϣ??
		Expression[] exps = this.exps;
		int keyCount = this.keyCount;
		int valCount = null == gathers ? 0 : gathers.length;

		Node []gathers = this.gathers; // ͳ?ƺ???????
		Table result = this.result;
		Object []keys = new Object[keyCount];
		ComputeStack stack = ctx.getComputeStack();
		Current current = new Current(table);
		stack.push(current);

		try {
			for (int i = 1, len = table.length(); i <= len; ++i) {
				current.setCurrent(i);
				// ???ݼ?¼???ɼ?ֵ
				for (int k = 0; k < keyCount; ++k) {
					keys[k] = exps[k].calculate(ctx);
				}

				BaseRecord r;
				int hash = hashUtil.hashCode(keys);
				if (groups[hash] == null) {
					groups[hash] = new ListBase1(INIT_GROUPSIZE);
					r = result.newLast(keys);
					groups[hash].add(r);
					for (int v = 0, f = keyCount; v < valCount; ++v, ++f) {
						Object val = gathers[v].gather(ctx);
						r.setNormalFieldValue(f, val);
					}
				} else {
					int index = HashUtil.bsearch_r(groups[hash], keys);
					if (index < 1) {
						r = result.newLast(keys);
						groups[hash].add(-index, r);
						for (int v = 0, f = keyCount; v < valCount; ++v, ++f) {
							Object val = gathers[v].gather(ctx);
							r.setNormalFieldValue(f, val);
						}
					} else {
						r = (BaseRecord)groups[hash].get(index);
						for (int v = 0, f = keyCount; v < valCount; ++v, ++f) {
							Object val = gathers[v].gather(r.getNormalFieldValue(f), ctx);
							r.setNormalFieldValue(f, val);
						}
					}
				}
			}
		} finally {
			stack.pop();
		}
	}

	private void addGroups_1(Sequence table, Context ctx) {
		ComputeStack stack = ctx.getComputeStack();
		Current current = new Current(table);
		stack.push(current);
		int i = 1;
		
		BaseRecord r = prevRecord;
		int valCount = this.valCount;
		Node []gathers = this.gathers;

		try {
			if (r == null) {
				r = prevRecord = result.newLast();				
				current.setCurrent(1);
				i++;
				
				for (int v = 0; v < valCount; ++v) {
					Object val = gathers[v].gather(ctx);
					r.setNormalFieldValue(v, val);
				}
			}
			
			for (int len = table.length(); i <= len; ++i) {
				current.setCurrent(i);
				for (int v = 0; v < valCount; ++v) {
					Object val = gathers[v].gather(r.getNormalFieldValue(v), ctx);
					r.setNormalFieldValue(v, val);
				}
			}
		} finally {
			stack.pop();
		}
	}
	
	private void addGroups_o(Sequence table, Context ctx) {
		Table result = this.result;
		BaseRecord r = prevRecord;
		Expression[] exps = this.exps;
		int keyCount = this.keyCount;
		int valCount = this.valCount;
		Node []gathers = this.gathers;
		
		Object[] keys = new Object[keyCount];
		ComputeStack stack = ctx.getComputeStack();
		Current current = new Current(table);
		stack.push(current);

		try {
			for (int i = 1, len = table.length(); i <= len; ++i) {
				current.setCurrent(i);
				for (int k = 0; k < keyCount; ++k) {
					keys[k] = exps[k].calculate(ctx);
				}

				boolean isSame = true;
				if (r == null) {
					r = result.newLast(keys);
					isSame = false;
				} else {
					for (int k = 0; k < keyCount; ++k) {
						if (Variant.compare(r.getNormalFieldValue(k), keys[k], true) != 0) {
							r = result.newLast(keys);
							isSame = false;
							break;
						}
					}
				}

				if (isSame) {
					for (int v = 0, f = keyCount; v < valCount; ++v, ++f) {
						Object val = gathers[v].gather(r.getNormalFieldValue(f), ctx);
						r.setNormalFieldValue(f, val);
					}
				} else {
					for (int v = 0, f = keyCount; v < valCount; ++v, ++f) {
						Object val = gathers[v].gather(ctx);
						r.setNormalFieldValue(f, val);
					}
				}
			}
		} finally {
			stack.pop();
		}
		
		prevRecord = r;
	}
	
	private void addGroups_i(Sequence table, Context ctx) {
		Table result = this.result;
		BaseRecord r = prevRecord;
		Expression exp = exps[0];
		int valCount = this.valCount;
		Node []gathers = this.gathers;

		ComputeStack stack = ctx.getComputeStack();
		Current current = new Current(table);
		stack.push(current);

		try {
			for (int i = 1, len = table.length(); i <= len; ++i) {
				current.setCurrent(i);
				Object val = exp.calculate(ctx);

				if (Variant.isTrue(val) || r == null) {
					r = result.newLast();
					r.setNormalFieldValue(0, val);
					
					for (int v = 0, f = 1; v < valCount; ++v, ++f) {
						val = gathers[v].gather(ctx);
						r.setNormalFieldValue(f, val);
					}
				} else {
					for (int v = 0, f = 1; v < valCount; ++v, ++f) {
						val = gathers[v].gather(r.getNormalFieldValue(f), ctx);
						r.setNormalFieldValue(f, val);
					}
				}
			}
		} finally {
			stack.pop();
		}
		
		prevRecord = r;
	}

	/**
	 * ???÷???????@nѡ??ʹ??
	 * @param groupCount
	 */
	public void setGroupCount(int groupCount) {
		result.insert(groupCount);
	}

	private void addGroups_n(Sequence table, Context ctx) {
		Table result = this.result;
		Expression exp = exps[0];
		int valCount = this.valCount;
		Node []gathers = this.gathers;

		ComputeStack stack = ctx.getComputeStack();
		Current current = new Current(table);
		stack.push(current);

		try {
			for (int i = 1, len = table.length(); i <= len; ++i) {
				current.setCurrent(i);
				Object obj = exp.calculate(ctx);
				if (!(obj instanceof Number)) {
					MessageManager mm = EngineMessage.get();
					throw new RQException("groups: " + mm.getMessage("engine.needIntExp"));
				}

				int index = ((Number)obj).intValue();
				if (index < 1) {
					// ????С??1?ķŹ???Ҫ?ˣ????ٱ????????ֵ??κ?һ????
					continue;
				}
				
				BaseRecord r = result.getRecord(index);
				if (r.getNormalFieldValue(0) == null) {
					r.setNormalFieldValue(0, obj);
					for (int v = 0, f = 1; v < valCount; ++v, ++f) {
						Object val = gathers[v].gather(ctx);
						r.setNormalFieldValue(f, val);
					}
				} else {
					for (int v = 0, f = 1; v < valCount; ++v, ++f) {
						Object val = gathers[v].gather(r.getNormalFieldValue(f), ctx);
						r.setNormalFieldValue(f, val);
					}
				}
			}
		} finally {
			stack.pop();
		}
	}
	
	private void addGroups_h(Sequence table, Context ctx) {
		Expression[] exps = this.exps;
		int keyCount = this.keyCount;
		int valCount = this.valCount;
		Node []gathers = this.gathers;
		Table result = this.result;
		SortedGroupsLink link = this.link;
		
		Object[] keys = new Object[keyCount];
		ComputeStack stack = ctx.getComputeStack();
		Current current = new Current(table);
		stack.push(current);

		try {
			for (int i = 1, len = table.length(); i <= len; ++i) {
				current.setCurrent(i);
				for (int k = 0; k < keyCount; ++k) {
					keys[k] = exps[k].calculate(ctx);
				}

				SortedGroupsLink.Node node = link.put(keys);
				BaseRecord r = node.getRecord();
				if (r == null) {
					r = result.newLast(keys);
					node.setReocrd(r);
					
					for (int v = 0, f = keyCount; v < valCount; ++v, ++f) {
						Object val = gathers[v].gather(ctx);
						r.setNormalFieldValue(f, val);
					}
				} else {
					for (int v = 0, f = keyCount; v < valCount; ++v, ++f) {
						Object val = gathers[v].gather(r.getNormalFieldValue(f), ctx);
						r.setNormalFieldValue(f, val);
					}
				}
			}
		} finally {
			stack.pop();
		}
	}
	
	/**
	 * ??·????ʱ?԰?????·?????????ϲ????ж??η?????ܣ??õ????յĻ??ܽ??
	 * @param results ????·?ķ????????ɵ?????
	 * @return ???յĻ??ܽ??
	 */
	public Object combineResult(Object []results) {
		int count = results.length;
		Sequence result = new Sequence();
		for (int i = 0; i < count; ++i) {
			if (results[i] instanceof Sequence) {
				result.addAll((Sequence)results[i]);
			}
		}
		
		// ??·?α갴?????ֶβ?ֵ?
		if (opt != null && opt.indexOf('o') != -1) {
			return result.derive("o");
		}
		
		int dcount = exps == null ? 0 : exps.length;
		int mcount = calcExps == null ? 0 : calcExps.length;
		Expression []exps2 = null;
		if (dcount > 0) {
			exps2 = new Expression[dcount];
			for (int i = 0, q = 1; i < dcount; ++i, ++q) {
				exps2[i] = new Expression(ctx, "#" + q);
			}
		}

		Expression []calcExps2 = null;
		if (mcount > 0) {
			calcExps2 = new Expression[mcount];
			for (int i = 0, q = dcount + 1; i < mcount; ++i, ++q) {
				Gather gather = (Gather)calcExps[i].getHome();
				gather.prepare(ctx);
				calcExps2[i] = gather.getRegatherExpression(q);
			}
		}

		return result.groups(exps2, names, calcExps2, calcNames, opt, ctx);
	}
	
	
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy