package edu.isi.karma.controller.command.worksheet; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; import org.json.JSONArray; import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import edu.isi.karma.controller.command.CommandException; import edu.isi.karma.controller.command.CommandType; import edu.isi.karma.controller.command.WorksheetSelectionCommand; import edu.isi.karma.controller.command.selection.SuperSelection; import edu.isi.karma.controller.command.selection.SuperSelectionManager; import edu.isi.karma.controller.update.ErrorUpdate; import edu.isi.karma.controller.update.UpdateContainer; import edu.isi.karma.controller.update.WorksheetDeleteUpdate; import edu.isi.karma.controller.update.WorksheetListUpdate; import edu.isi.karma.controller.update.WorksheetUpdateFactory; import edu.isi.karma.er.helper.CloneTableUtils; import edu.isi.karma.modeling.alignment.Alignment; import edu.isi.karma.modeling.alignment.AlignmentManager; import edu.isi.karma.rep.HNode; import edu.isi.karma.rep.HNode.HNodeType; import edu.isi.karma.rep.HTable; import edu.isi.karma.rep.HashValueManager; import edu.isi.karma.rep.Node; import edu.isi.karma.rep.RepFactory; import edu.isi.karma.rep.Row; import edu.isi.karma.rep.Table; import edu.isi.karma.rep.Worksheet; import edu.isi.karma.rep.Workspace; import edu.isi.karma.rep.metadata.WorksheetProperties.Property; import edu.isi.karma.util.CommandInputJSONUtil; import edu.isi.karma.util.JSONUtil; import edu.isi.karma.util.Util; public class GroupByCommand extends WorksheetSelectionCommand { private String newWorksheetId; private String newHNodeId; private String hNodeId; private static Logger logger = LoggerFactory .getLogger(GroupByCommand.class); private String label; public enum JsonKeys { updateType, hNodeId, worksheetId } protected GroupByCommand(String id, String model, String worksheetId, String hTableId, String hNodeId, String selectionId) { super(id, model, worksheetId, selectionId); this.hNodeId = hNodeId; addTag(CommandTag.Transformation); } @Override public String getCommandName() { return GroupByCommand.class.getSimpleName(); } @Override public String getTitle() { return "GroupBy"; } @Override public String getDescription() { return label; } @Override public CommandType getCommandType() { return CommandType.undoable; } @Override public UpdateContainer doIt(Workspace workspace) throws CommandException { inputColumns.clear(); outputColumns.clear(); RepFactory factory = workspace.getFactory(); Worksheet oldws = workspace.getWorksheet(worksheetId); Object para = JSONUtil.createJson(this.getInputParameterJson()); List<String> hnodeIDs = new ArrayList<>(); List<HNode> keyhnodes = new ArrayList<>(); List<HNode> valuehnodes = new ArrayList<>(); JSONArray checked = (JSONArray) JSONUtil.createJson(CommandInputJSONUtil.getStringValue("values", (JSONArray)para)); HTable ht; if (hNodeId.compareTo("") != 0) ht = factory.getHTable(factory.getHNode(hNodeId).getHTableId()); else ht = oldws.getHeaders(); for (int i = 0; i < checked.length(); i++) { JSONObject t = (checked.getJSONObject(i)); hnodeIDs.add((String) t.get("value")); keyhnodes.add(ht.getHNode((String) t.get("value"))); } for (HNode oldhnode : ht.getHNodes()) { boolean found = false; for (HNode keynode : keyhnodes) { if (keynode.getId().compareTo(oldhnode.getId()) == 0) found = true; } if (!found) valuehnodes.add(oldhnode); } this.label = factory.getHNode(hNodeId).getParentColumnName(factory); String sep = " > "; for (HNode keynode : keyhnodes) { this.label += sep + keynode.getColumnName(); sep = ", "; } Worksheet newws = null; if (ht == oldws.getHeaders()) newws = groupByTopLevel(oldws, workspace, hnodeIDs, keyhnodes, valuehnodes, factory); else { inputColumns.addAll(hnodeIDs); groupByNestedTable(oldws, workspace, ht, hnodeIDs, keyhnodes, valuehnodes, factory); } try{ UpdateContainer c = new UpdateContainer(); WorksheetUpdateFactory.detectSelectionStatusChange(worksheetId, workspace, this); c.add(new WorksheetListUpdate()); if (newws == null) c.append(WorksheetUpdateFactory.createRegenerateWorksheetUpdates(oldws.getId(), getSuperSelection(oldws), workspace.getContextId())); if (newws != null) { c.append(WorksheetUpdateFactory.createRegenerateWorksheetUpdates(newws.getId(), SuperSelectionManager.DEFAULT_SELECTION, workspace.getContextId())); //c.append(WorksheetUpdateFactory.createWorksheetHierarchicalAndCleaningResultsUpdates(newws.getId())); Alignment alignment = AlignmentManager.Instance().createAlignment(workspace.getId(), newws.getId(), workspace.getOntologyManager()); c.append(WorksheetUpdateFactory.createSemanticTypesAndSVGAlignmentUpdates(newws.getId(), workspace)); } //c.append(WorksheetUpdateFactory.createWorksheetHierarchicalAndCleaningResultsUpdates(oldws.getId())); c.append(computeAlignmentAndSemanticTypesAndCreateUpdates(workspace)); return c; } catch (Exception e) { logger.error("Error in UnfoldCommand" + e.toString()); Util.logException(logger, e); return new UpdateContainer(new ErrorUpdate(e.getMessage())); } } @Override public UpdateContainer undoIt(Workspace workspace) { UpdateContainer c = new UpdateContainer(); if (this.newWorksheetId != null) { workspace.removeWorksheet(newWorksheetId); workspace.getFactory().removeWorksheet(newWorksheetId, workspace.getCommandHistory()); c.add(new WorksheetListUpdate()); c.add(new WorksheetDeleteUpdate(newWorksheetId)); } if (this.newHNodeId != null) { Worksheet worksheet = workspace.getWorksheet(worksheetId); HNode ndid = workspace.getFactory().getHNode(newHNodeId); HTable currentTable = workspace.getFactory().getHTable(ndid.getHTableId()); ndid.removeNestedTable(); //remove the new column currentTable.removeHNode(newHNodeId, worksheet); c.append(WorksheetUpdateFactory.createRegenerateWorksheetUpdates(worksheetId, getSuperSelection(worksheet), workspace.getContextId())); c.append(computeAlignmentAndSemanticTypesAndCreateUpdates(workspace)); } return c; } private Worksheet groupByTopLevel(Worksheet oldws, Workspace workspace, List<String> hnodeIDs, List<HNode> keyhnodes, List<HNode> valuehnodes, RepFactory factory) { SuperSelection selection = getSuperSelection(oldws); Worksheet newws = factory.createWorksheet("GroupBy: " + oldws.getTitle(), workspace, oldws.getEncoding()); newws.getMetadataContainer().getWorksheetProperties().setPropertyValue(Property.sourceType, oldws.getMetadataContainer().getWorksheetProperties().getPropertyValue(Property.sourceType)); HTable newht = newws.getHeaders(); ArrayList<Row> rows = oldws.getDataTable().getRows(0, oldws.getDataTable().getNumRows(), selection); HTable oldht = oldws.getHeaders(); Map<String, ArrayList<String>> hash = new TreeMap<>(); for (Row row : rows) { String hashValue = HashValueManager.getHashValue(row, hnodeIDs); ArrayList<String> ids = hash.get(hashValue); if (ids == null) ids = new ArrayList<>(); ids.add(row.getId()); hash.put(hashValue, ids); } CloneTableUtils.cloneHTable(newht, newws, factory, keyhnodes, false); newht.addHNode("Values", HNodeType.Transformation, newws, factory); HTable newValueTable = newht.getHNodeFromColumnName("Values").addNestedTable("Table for values", newws, factory); CloneTableUtils.cloneHTable(newValueTable, newws, factory, valuehnodes, false); for (Entry<String, ArrayList<String>> stringArrayListEntry : hash.entrySet()) { ArrayList<String> r = stringArrayListEntry.getValue(); Row lastRow = CloneTableUtils.cloneDataTable(factory.getRow(r.get(0)), newws.getDataTable(), newht, keyhnodes, factory, selection); for (String rowid : r) { Row cur = factory.getRow(rowid); Table dataTable = lastRow.getNeighborByColumnName("Values", factory).getNestedTable(); CloneTableUtils.cloneDataTable(cur, dataTable, newValueTable, valuehnodes, factory, selection); } } newWorksheetId = newws.getId(); return newws; } private void groupByNestedTable(Worksheet oldws, Workspace workspace, HTable ht, List<String> hnodeIDs, List<HNode> keyhnodes, List<HNode> valuehnodes, RepFactory factory) { SuperSelection selection = getSuperSelection(oldws); HTable parentHT = ht.getParentHNode().getHTable(factory); List<Table> parentTables = new ArrayList<>(); CloneTableUtils.getDatatable(oldws.getDataTable(), parentHT,parentTables, selection); ArrayList<Row> parentRows = new ArrayList<>(); for (Table tmp : parentTables) { for (Row row : tmp.getRows(0, tmp.getNumRows(), selection)) { parentRows.add(row); } } HNode newNode = parentHT.addHNode(parentHT.getNewColumnName("GroupBy"), HNodeType.Transformation, oldws, factory); newHNodeId = newNode.getId(); outputColumns.add(newNode.getId()); HTable newht = newNode.addNestedTable(newNode.getColumnName(), oldws, factory); for (Entry<String, String> entry : CloneTableUtils.cloneHTable(newht, oldws, factory, keyhnodes, false).entrySet()) { outputColumns.add(entry.getValue()); } outputColumns.add(newht.addHNode("Values", HNodeType.Transformation, oldws, factory).getId()); HTable newValueTable = newht.getHNodeFromColumnName("Values").addNestedTable("Table for values", oldws, factory); for (Entry<String, String> entry : CloneTableUtils.cloneHTable(newValueTable, oldws, factory, valuehnodes, false).entrySet()) { outputColumns.add(entry.getValue()); } for (Row parentRow : parentRows) { Table t = null; for (Node node : parentRow.getNodes()) { if (node.hasNestedTable() && node.getNestedTable().getHTableId().compareTo(ht.getId()) == 0) { t = node.getNestedTable(); break; } } ArrayList<Row> rows = t.getRows(0, t.getNumRows(), selection); Map<String, ArrayList<String>> hash = new TreeMap<>(); for (Row row : rows) { String hashValue = HashValueManager.getHashValue(row, hnodeIDs); ArrayList<String> ids = hash.get(hashValue); if (ids == null) ids = new ArrayList<>(); ids.add(row.getId()); hash.put(hashValue, ids); } for (Entry<String, ArrayList<String>> stringArrayListEntry : hash.entrySet()) { ArrayList<String> r = stringArrayListEntry.getValue(); Node node = parentRow.getNeighbor(newNode.getId()); Row lastRow = CloneTableUtils.cloneDataTable(factory.getRow(r.get(0)), node.getNestedTable(), newht, keyhnodes, factory, selection); for (String rowid : r) { Row cur = factory.getRow(rowid); Table dataTable = lastRow.getNeighborByColumnName("Values", factory).getNestedTable(); CloneTableUtils.cloneDataTable(cur, dataTable, newValueTable, valuehnodes, factory, selection); } } } } }