Added support in protograph for specifying several column names per cell-as nodes.
Started to add support for conditional links in protograph. The UI is not hooked up with. git-svn-id: http://google-refine.googlecode.com/svn/trunk@1136 7d457c2a-affb-35e4-300a-418c747d4874
This commit is contained in:
parent
b8ad56c6db
commit
5cb3f924f6
@ -0,0 +1,31 @@
|
||||
package com.google.gridworks.protograph;
|
||||
|
||||
import com.google.gridworks.model.Column;
|
||||
import com.google.gridworks.model.Project;
|
||||
import com.google.gridworks.model.Row;
|
||||
|
||||
|
||||
public class BooleanColumnCondition implements Condition {
|
||||
final public String columnName;
|
||||
|
||||
public BooleanColumnCondition(String columnName) {
|
||||
this.columnName = columnName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(Project project, int rowIndex, Row row) {
|
||||
Column column = project.columnModel.getColumnByName(columnName);
|
||||
if (column != null) {
|
||||
Object o = row.getCellValue(column.getCellIndex());
|
||||
if (o != null) {
|
||||
if (o instanceof Boolean) {
|
||||
return ((Boolean) o).booleanValue();
|
||||
} else {
|
||||
return Boolean.parseBoolean(o.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -9,11 +9,8 @@ public class CellKeyNode extends CellNode {
|
||||
final public FreebaseTopic namespace;
|
||||
|
||||
public CellKeyNode(
|
||||
String columnName,
|
||||
FreebaseTopic namespace
|
||||
) {
|
||||
super(columnName);
|
||||
|
||||
this.namespace = namespace;
|
||||
}
|
||||
|
||||
@ -22,7 +19,14 @@ public class CellKeyNode extends CellNode {
|
||||
|
||||
writer.object();
|
||||
writer.key("nodeType"); writer.value("cell-as-key");
|
||||
writer.key("columnName"); writer.value(columnName);
|
||||
|
||||
writer.key("columnNames");
|
||||
writer.array();
|
||||
for (String name : columnNames) {
|
||||
writer.value(name);
|
||||
}
|
||||
writer.endArray();
|
||||
|
||||
writer.key("namespace"); namespace.write(writer, options);
|
||||
writer.endObject();
|
||||
}
|
||||
|
@ -1,11 +1,8 @@
|
||||
package com.google.gridworks.protograph;
|
||||
|
||||
abstract public class CellNode implements Node {
|
||||
final public String columnName;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public CellNode(
|
||||
String columnName
|
||||
) {
|
||||
this.columnName = columnName;
|
||||
}
|
||||
abstract public class CellNode implements Node {
|
||||
final public List<String> columnNames = new LinkedList<String>();
|
||||
}
|
||||
|
@ -12,11 +12,8 @@ public class CellTopicNode extends CellNode implements NodeWithLinks {
|
||||
final public List<Link> links = new LinkedList<Link>();
|
||||
|
||||
public CellTopicNode(
|
||||
String columnName,
|
||||
FreebaseType type
|
||||
) {
|
||||
super(columnName);
|
||||
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@ -25,7 +22,12 @@ public class CellTopicNode extends CellNode implements NodeWithLinks {
|
||||
|
||||
writer.object();
|
||||
writer.key("nodeType"); writer.value("cell-as-topic");
|
||||
writer.key("columnName"); writer.value(columnName);
|
||||
writer.key("columnNames");
|
||||
writer.array();
|
||||
for (String name : columnNames) {
|
||||
writer.value(name);
|
||||
}
|
||||
writer.endArray();
|
||||
if (type != null) {
|
||||
writer.key("type"); type.write(writer, options);
|
||||
}
|
||||
|
@ -10,12 +10,9 @@ public class CellValueNode extends CellNode {
|
||||
final public String lang;
|
||||
|
||||
public CellValueNode(
|
||||
String columnName,
|
||||
String valueType,
|
||||
String lang
|
||||
) {
|
||||
super(columnName);
|
||||
|
||||
this.valueType = valueType;
|
||||
this.lang = lang;
|
||||
}
|
||||
@ -25,7 +22,12 @@ public class CellValueNode extends CellNode {
|
||||
|
||||
writer.object();
|
||||
writer.key("nodeType"); writer.value("cell-as-value");
|
||||
writer.key("columnName"); writer.value(columnName);
|
||||
writer.key("columnNames");
|
||||
writer.array();
|
||||
for (String name : columnNames) {
|
||||
writer.value(name);
|
||||
}
|
||||
writer.endArray();
|
||||
writer.key("valueType"); writer.value(valueType);
|
||||
writer.key("lang"); writer.value(lang);
|
||||
writer.endObject();
|
||||
|
8
main/src/com/google/gridworks/protograph/Condition.java
Normal file
8
main/src/com/google/gridworks/protograph/Condition.java
Normal file
@ -0,0 +1,8 @@
|
||||
package com.google.gridworks.protograph;
|
||||
|
||||
import com.google.gridworks.model.Project;
|
||||
import com.google.gridworks.model.Row;
|
||||
|
||||
public interface Condition {
|
||||
public boolean test(Project project, int rowIndex, Row row);
|
||||
}
|
@ -10,11 +10,13 @@ import com.google.gridworks.Jsonizable;
|
||||
public class Link implements Jsonizable {
|
||||
final public FreebaseProperty property;
|
||||
final public Node target;
|
||||
final public Condition condition;
|
||||
final public boolean load;
|
||||
|
||||
public Link(FreebaseProperty property, Node target, boolean load) {
|
||||
public Link(FreebaseProperty property, Node target, Condition condition, boolean load) {
|
||||
this.property = property;
|
||||
this.target = target;
|
||||
this.condition = condition;
|
||||
this.load = load;
|
||||
}
|
||||
|
||||
|
@ -45,27 +45,34 @@ public class Protograph implements OverlayModel {
|
||||
|
||||
String nodeType = o.getString("nodeType");
|
||||
if (nodeType.startsWith("cell-as-")) {
|
||||
String columnName = o.getString("columnName");
|
||||
|
||||
if ("cell-as-topic".equals(nodeType)) {
|
||||
if (o.has("type")) {
|
||||
node = new CellTopicNode(
|
||||
columnName,
|
||||
reconstructType(o.getJSONObject("type"))
|
||||
);
|
||||
}
|
||||
} else if ("cell-as-value".equals(nodeType)) {
|
||||
node = new CellValueNode(
|
||||
columnName,
|
||||
o.getString("valueType"),
|
||||
o.getString("lang")
|
||||
);
|
||||
} else if ("cell-as-key".equals(nodeType)) {
|
||||
node = new CellKeyNode(
|
||||
columnName,
|
||||
reconstructTopic(o.getJSONObject("namespace"))
|
||||
);
|
||||
}
|
||||
|
||||
if (o.has("columnName") && !o.isNull("columnName")) {
|
||||
((CellNode) node).columnNames.add(o.getString("columnName"));
|
||||
}
|
||||
if (o.has("columnNames") && !o.isNull("columnNames")) {
|
||||
JSONArray columnNames = o.getJSONArray("columnNames");
|
||||
int count = columnNames.length();
|
||||
|
||||
for (int c = 0; c < count; c++) {
|
||||
((CellNode) node).columnNames.add(columnNames.getString(c));
|
||||
}
|
||||
}
|
||||
} else if ("topic".equals(nodeType)) {
|
||||
node = new FreebaseTopicNode(reconstructTopic(o.getJSONObject("topic")));
|
||||
} else if ("value".equals(nodeType)) {
|
||||
@ -86,11 +93,20 @@ public class Protograph implements OverlayModel {
|
||||
|
||||
for (int j = 0; j < linkCount; j++) {
|
||||
JSONObject oLink = links.getJSONObject(j);
|
||||
Condition condition = null;
|
||||
|
||||
if (oLink.has("condition") && !oLink.isNull("condition")) {
|
||||
JSONObject oCondition = oLink.getJSONObject("condition");
|
||||
if (oCondition.has("columnName") && !oCondition.isNull("columnName")) {
|
||||
condition = new BooleanColumnCondition(oCondition.getString("columnName"));
|
||||
}
|
||||
}
|
||||
|
||||
node2.addLink(new Link(
|
||||
reconstructProperty(oLink.getJSONObject("property")),
|
||||
oLink.has("target") && !oLink.isNull("target") ?
|
||||
reconstructNode(oLink.getJSONObject("target")) : null,
|
||||
condition,
|
||||
oLink.has("load") && !oLink.isNull("load") ?
|
||||
oLink.getBoolean("load") : true
|
||||
));
|
||||
|
@ -261,7 +261,9 @@ public class MqlwriteLikeTransposedNodeFactory implements TransposedNodeFactory
|
||||
TransposedNode parentNode,
|
||||
Link link,
|
||||
CellNode node,
|
||||
int rowIndex, Cell cell) {
|
||||
int rowIndex,
|
||||
int cellIndex,
|
||||
Cell cell) {
|
||||
|
||||
JsonTransposedNode tnode = null;
|
||||
if (node instanceof CellTopicNode) {
|
||||
|
@ -21,6 +21,7 @@ public interface TransposedNodeFactory {
|
||||
Link link,
|
||||
CellNode node,
|
||||
int rowIndex,
|
||||
int cellIndex,
|
||||
Cell cell
|
||||
);
|
||||
|
||||
|
@ -97,16 +97,19 @@ public class Transposer {
|
||||
Node node,
|
||||
Context context
|
||||
) {
|
||||
TransposedNode tnode = null;
|
||||
List<TransposedNode> tnodes = new LinkedList<TransposedNode>();
|
||||
|
||||
TransposedNode parentNode = context.parent == null ? null : context.parent.transposedNode;
|
||||
Link link = context.parent == null ? null : context.link;
|
||||
|
||||
if (node instanceof CellNode) {
|
||||
CellNode node2 = (CellNode) node;
|
||||
Column column = project.columnModel.getColumnByName(node2.columnName);
|
||||
for (String columnName : node2.columnNames) {
|
||||
Column column = project.columnModel.getColumnByName(columnName);
|
||||
if (column != null) {
|
||||
Cell cell = row.getCell(column.getCellIndex());
|
||||
int cellIndex = column.getCellIndex();
|
||||
|
||||
Cell cell = row.getCell(cellIndex);
|
||||
if (cell != null && ExpressionUtils.isNonBlankData(cell.value)) {
|
||||
if (node2 instanceof CellTopicNode &&
|
||||
(cell.recon == null || cell.recon.judgment == Judgment.None)) {
|
||||
@ -118,66 +121,67 @@ public class Transposer {
|
||||
return;
|
||||
}
|
||||
|
||||
tnode = nodeFactory.transposeCellNode(
|
||||
tnodes.add(nodeFactory.transposeCellNode(
|
||||
parentNode,
|
||||
link,
|
||||
node2,
|
||||
rowIndex,
|
||||
cellIndex,
|
||||
cell
|
||||
);
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (node instanceof AnonymousNode) {
|
||||
tnode = nodeFactory.transposeAnonymousNode(
|
||||
tnodes.add(nodeFactory.transposeAnonymousNode(
|
||||
parentNode,
|
||||
link,
|
||||
(AnonymousNode) node,
|
||||
rowIndex
|
||||
);
|
||||
));
|
||||
} else if (node instanceof FreebaseTopicNode) {
|
||||
tnode = nodeFactory.transposeTopicNode(
|
||||
tnodes.add(nodeFactory.transposeTopicNode(
|
||||
parentNode,
|
||||
link,
|
||||
(FreebaseTopicNode) node,
|
||||
rowIndex
|
||||
);
|
||||
));
|
||||
} else if (node instanceof ValueNode) {
|
||||
tnode = nodeFactory.transposeValueNode(
|
||||
tnodes.add(nodeFactory.transposeValueNode(
|
||||
parentNode,
|
||||
link,
|
||||
(ValueNode) node,
|
||||
rowIndex
|
||||
);
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if (tnode != null) {
|
||||
context.transposedNode = tnode;
|
||||
context.nullifySubContextNodes();
|
||||
} /*
|
||||
else, previous rows might have set the context transposed node already,
|
||||
and we simply inherit that transposed node.
|
||||
*/
|
||||
|
||||
if (node instanceof NodeWithLinks && context.transposedNode != null) {
|
||||
if (node instanceof NodeWithLinks) {
|
||||
NodeWithLinks node2 = (NodeWithLinks) node;
|
||||
|
||||
int linkCount = node2.getLinkCount();
|
||||
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
Link link2 = node2.getLink(i);
|
||||
if (link2.condition == null || link2.condition.test(project, rowIndex, row)) {
|
||||
for (TransposedNode tnode : tnodes) {
|
||||
context.transposedNode = tnode;
|
||||
context.nullifySubContextNodes();
|
||||
|
||||
descend(
|
||||
project,
|
||||
protograph,
|
||||
nodeFactory,
|
||||
rowIndex,
|
||||
row,
|
||||
node2.getLink(i).getTarget(),
|
||||
link2.getTarget(),
|
||||
context.subContexts.get(i)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class Context {
|
||||
TransposedNode transposedNode;
|
||||
|
@ -352,17 +352,19 @@ public class TripleLoaderTransposedNodeFactory implements TransposedNodeFactory
|
||||
if (newTopicVars.containsKey(cell.recon.id)) {
|
||||
id = newTopicVars.get(cell.recon.id);
|
||||
} else {
|
||||
long var = 0;
|
||||
if (varPool.containsKey(node.columnName)) {
|
||||
var = varPool.get(node.columnName);
|
||||
}
|
||||
varPool.put(node.columnName, var + 1);
|
||||
Column column = project.columnModel.getColumnByCellIndex(cellIndex);
|
||||
String columnName = column.getName();
|
||||
|
||||
id = "$" + node.columnName.replaceAll("\\W+", "_") + "_" + var;
|
||||
long var = 0;
|
||||
if (varPool.containsKey(columnName)) {
|
||||
var = varPool.get(columnName);
|
||||
}
|
||||
varPool.put(columnName, var + 1);
|
||||
|
||||
id = "$" + columnName.replaceAll("\\W+", "_") + "_" + var;
|
||||
|
||||
String typeID = node.type.id;
|
||||
|
||||
Column column = project.columnModel.getColumnByName(node.columnName);
|
||||
ReconConfig reconConfig = column.getReconConfig();
|
||||
if (reconConfig instanceof StandardReconConfig) {
|
||||
typeID = ((StandardReconConfig) reconConfig).typeID;
|
||||
@ -511,13 +513,11 @@ public class TripleLoaderTransposedNodeFactory implements TransposedNodeFactory
|
||||
Link link,
|
||||
CellNode node,
|
||||
int rowIndex,
|
||||
int cellIndex,
|
||||
Cell cell) {
|
||||
|
||||
WritingTransposedNode parentNode2 = (WritingTransposedNode) parentNode;
|
||||
|
||||
Column column = project.columnModel.getColumnByName(node.columnName);
|
||||
int cellIndex = column != null ? column.getCellIndex() : -1;
|
||||
|
||||
WritingTransposedNode tnode = null;
|
||||
if (node instanceof CellTopicNode) {
|
||||
if (cell.recon != null &&
|
||||
|
@ -3,6 +3,11 @@ SchemaAlignmentDialog.UINode = function(dialog, node, table, options) {
|
||||
this._node = node;
|
||||
this._options = options;
|
||||
|
||||
if ("columnName" in this._node) {
|
||||
this._node.columnNames = [ this._node.columnName ];
|
||||
delete this._node.columnName;
|
||||
}
|
||||
|
||||
this._linkUIs = [];
|
||||
this._detailsRendered = false;
|
||||
|
||||
@ -74,13 +79,19 @@ SchemaAlignmentDialog.UINode.prototype._renderMain = function() {
|
||||
this._node.nodeType == "cell-as-value" ||
|
||||
this._node.nodeType == "cell-as-key") {
|
||||
|
||||
if ("columnName" in this._node) {
|
||||
a.html(" cell");
|
||||
if ("columnNames" in this._node) {
|
||||
for (var c = 0; c < this._node.columnNames.length; c++) {
|
||||
if (c > 0) {
|
||||
$('<span>').text(", ").appendTo(a);
|
||||
}
|
||||
|
||||
$('<span></span>')
|
||||
.text(this._node.columnName)
|
||||
$('<span>')
|
||||
.text(this._node.columnNames[c])
|
||||
.addClass("schema-alignment-node-column")
|
||||
.prependTo(a);
|
||||
.appendTo(a);
|
||||
}
|
||||
|
||||
$('<span>').text(this._node.columnNames.length > 1 ? " cells" : " cell").appendTo(a);
|
||||
} else {
|
||||
a.html(this._options.mustBeCellTopic ? "Which column?" : "Configure...");
|
||||
}
|
||||
@ -229,7 +240,7 @@ SchemaAlignmentDialog.UINode.prototype._showColumnPopupMenu = function(elmt) {
|
||||
label: columns[index].name,
|
||||
click: function() {
|
||||
self._node.nodeType = "cell-as-topic";
|
||||
self._node.columnName = columns[index].name;
|
||||
self._node.columnNames = [ columns[index].name ];
|
||||
self._showExpandable();
|
||||
self._renderMain();
|
||||
}
|
||||
@ -398,11 +409,18 @@ SchemaAlignmentDialog.UINode.prototype._showNodeConfigDialog = function() {
|
||||
.attr("cellpadding", "0")
|
||||
.appendTo(elmts.divColumns)[0];
|
||||
|
||||
var columnMap = {};
|
||||
if ("columnNames" in self._node) {
|
||||
for (var i = 0; i < self._node.columnNames.length; i++) {
|
||||
columnMap[self._node.columnNames[i]] = true;
|
||||
}
|
||||
}
|
||||
|
||||
var makeColumnChoice = function(column, columnIndex) {
|
||||
var tr = tableColumns.insertRow(tableColumns.rows.length);
|
||||
|
||||
var radio = $('<input />')
|
||||
.attr("type", "radio")
|
||||
.attr("type", "checkbox")
|
||||
.attr("value", column.name)
|
||||
.attr("name", "schema-align-node-dialog-column")
|
||||
.appendTo(tr.insertCell(0))
|
||||
@ -420,9 +438,7 @@ SchemaAlignmentDialog.UINode.prototype._showNodeConfigDialog = function() {
|
||||
}
|
||||
});
|
||||
|
||||
if ((!("columnName" in self._node) || !self._node.columnName) && columnIndex === 0) {
|
||||
radio.attr("checked", "true");
|
||||
} else if (column.name == self._node.columnName) {
|
||||
if (column.name in columnMap) {
|
||||
radio.attr("checked", "true");
|
||||
}
|
||||
|
||||
@ -539,7 +555,14 @@ SchemaAlignmentDialog.UINode.prototype._showNodeConfigDialog = function() {
|
||||
};
|
||||
if (node.nodeType == "cell-as") {
|
||||
node.nodeType = $("input[name='schema-align-node-dialog-node-subtype']:checked")[0].value;
|
||||
node.columnName = $("input[name='schema-align-node-dialog-column']:checked")[0].value;
|
||||
node.columnNames = $("input[name='schema-align-node-dialog-column']:checked").map(function() {
|
||||
return this.getAttribute("value");
|
||||
}).get();
|
||||
|
||||
if (node.columnNames.length == 0) {
|
||||
alert("You must select at least one column.");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (node.nodeType == "cell-as-topic") {
|
||||
node.createForNoReconMatch = elmts.radioNodeTypeCellAsTopicCreate[0].checked;
|
||||
@ -631,14 +654,14 @@ SchemaAlignmentDialog.UINode.prototype.getJSON = function() {
|
||||
var getLinks = false;
|
||||
|
||||
if (this._node.nodeType.match(/^cell-as-/)) {
|
||||
if (!("columnName" in this._node) || !this._node.columnName) {
|
||||
if (!("columnNames" in this._node) || !this._node.columnNames) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this._node.nodeType == "cell-as-topic") {
|
||||
result = {
|
||||
nodeType: this._node.nodeType,
|
||||
columnName: this._node.columnName,
|
||||
columnNames: this._node.columnNames,
|
||||
type: "type" in this._node ? cloneDeep(this._node.type) : { "id" : "/common/topic", "name" : "Topic", "cvt" : false },
|
||||
createForNoReconMatch: "createForNoReconMatch" in this._node ? this._node.createForNoReconMatch : true
|
||||
};
|
||||
@ -646,7 +669,7 @@ SchemaAlignmentDialog.UINode.prototype.getJSON = function() {
|
||||
} else if (this._node.nodeType == "cell-as-value") {
|
||||
result = {
|
||||
nodeType: this._node.nodeType,
|
||||
columnName: this._node.columnName,
|
||||
columnNames: this._node.columnNames,
|
||||
valueType: "valueType" in this._node ? this._node.valueType : "/type/text",
|
||||
lang: "lang" in this._node ? this._node.lang : "/lang/en"
|
||||
};
|
||||
@ -656,7 +679,7 @@ SchemaAlignmentDialog.UINode.prototype.getJSON = function() {
|
||||
}
|
||||
result = {
|
||||
nodeType: this._node.nodeType,
|
||||
columnName: this._node.columnName,
|
||||
columnNames: this._node.columnNames,
|
||||
type: cloneDeep(this._node.namespace)
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user