Added support for including dependent rows in row visiting. Facets still don't count them, though.

git-svn-id: http://google-refine.googlecode.com/svn/trunk@282 7d457c2a-affb-35e4-300a-418c747d4874
This commit is contained in:
David Huynh 2010-03-12 01:06:23 +00:00
parent 7e2667ab45
commit af3cb76056
21 changed files with 125 additions and 93 deletions

View File

@ -9,10 +9,12 @@ import com.metaweb.gridworks.model.Row;
public class ConjunctiveFilteredRows implements FilteredRows {
final protected List<RowFilter> _rowFilters = new LinkedList<RowFilter>();
final protected boolean _contextual;
final protected boolean _includeContextual;
final protected boolean _includeDependent;
public ConjunctiveFilteredRows(boolean contextual) {
_contextual = contextual;
public ConjunctiveFilteredRows(boolean includeContextual, boolean includeDependent) {
_includeContextual = includeContextual;
_includeDependent = includeDependent;
}
public void add(RowFilter rowFilter) {
@ -20,63 +22,66 @@ public class ConjunctiveFilteredRows implements FilteredRows {
}
public void accept(Project project, RowVisitor visitor) {
if (_contextual) {
contextualAccept(project, visitor);
} else {
simpleAccept(project, visitor);
}
}
protected void simpleAccept(Project project, RowVisitor visitor) {
for (int i = 0; i < project.rows.size(); i++) {
Row row = project.rows.get(i);
boolean ok = true;
for (RowFilter rowFilter : _rowFilters) {
if (!rowFilter.filterRow(project, i, row)) {
ok = false;
break;
}
}
if (ok) {
visitor.visit(project, i, row, false);
}
}
}
protected void contextualAccept(Project project, RowVisitor visitor) {
int lastVisitedRow = -1;
int lastRecordRowAccepted = -1;
for (int i = 0; i < project.rows.size(); i++) {
int c = project.rows.size();
for (int i = 0; i < c; i++) {
Row row = project.rows.get(i);
boolean ok = true;
for (RowFilter rowFilter : _rowFilters) {
if (!rowFilter.filterRow(project, i, row)) {
ok = false;
break;
}
}
if (checkRow(project, i, row)) {
if (row.recordIndex >= 0) {
// this is a record row itself
if (ok) {
if (row.contextRows != null && lastVisitedRow < i - 1) {
for (int contextRowIndex : row.contextRows) {
if (contextRowIndex > lastVisitedRow) {
visitor.visit(
project,
contextRowIndex,
project.rows.get(contextRowIndex),
true
);
lastVisitedRow = contextRowIndex;
}
lastRecordRowAccepted = i;
}
visitRow(project, visitor, i, row, lastVisitedRow);
lastVisitedRow = i;
} else if (
_includeDependent &&
row.recordIndex < 0 &&
row.contextRows != null &&
row.contextRows.size() > 0) {
if (row.contextRows.get(0) == lastRecordRowAccepted) {
visitor.visit(project, i, row, false, true);
lastVisitedRow = i;
}
}
}
}
protected void visitRow(Project project, RowVisitor visitor, int rowIndex, Row row, int lastVisitedRow) {
if (_includeContextual) {
if (row.contextRows != null && lastVisitedRow < rowIndex - 1) {
for (int contextRowIndex : row.contextRows) {
if (contextRowIndex > lastVisitedRow) {
visitor.visit(
project,
contextRowIndex,
project.rows.get(contextRowIndex),
true,
false
);
lastVisitedRow = contextRowIndex;
}
}
}
visitor.visit(project, i, row, false);
lastVisitedRow = i;
visitor.visit(project, rowIndex, row, false, false);
} else {
visitor.visit(project, rowIndex, row, false, false);
}
}
protected boolean checkRow(Project project, int rowIndex, Row row) {
for (RowFilter rowFilter : _rowFilters) {
if (!rowFilter.filterRow(project, rowIndex, row)) {
return false;
}
}
return true;
}
}

View File

@ -20,17 +20,18 @@ import com.metaweb.gridworks.model.Project;
public class Engine implements Jsonizable {
protected Project _project;
protected List<Facet> _facets = new LinkedList<Facet>();
protected boolean _includeDependent;
public Engine(Project project) {
_project = project;
}
public FilteredRows getAllFilteredRows(boolean contextual) {
return getFilteredRows(null, contextual);
public FilteredRows getAllFilteredRows(boolean includeContextual) {
return getFilteredRows(null, includeContextual);
}
public FilteredRows getFilteredRows(Facet except, boolean contextual) {
ConjunctiveFilteredRows cfr = new ConjunctiveFilteredRows(contextual);
public FilteredRows getFilteredRows(Facet except, boolean includeContextual) {
ConjunctiveFilteredRows cfr = new ConjunctiveFilteredRows(includeContextual, _includeDependent);
for (Facet facet : _facets) {
if (facet != except) {
RowFilter rowFilter = facet.getRowFilter();
@ -64,6 +65,10 @@ public class Engine implements Jsonizable {
_facets.add(facet);
}
}
if (o.has("includeDependent") && !o.isNull("includeDependent")) {
_includeDependent = o.getBoolean("includeDependent");
}
}
public void computeFacets() throws JSONException {
@ -78,11 +83,13 @@ public class Engine implements Jsonizable {
throws JSONException {
writer.object();
writer.key("facets"); writer.array();
for (Facet facet : _facets) {
facet.write(writer, options);
}
writer.endArray();
writer.key("facets");
writer.array();
for (Facet facet : _facets) {
facet.write(writer, options);
}
writer.endArray();
writer.key("includeDependent"); writer.value(_includeDependent);
writer.endObject();
}
}

View File

@ -4,6 +4,11 @@ import com.metaweb.gridworks.model.Project;
import com.metaweb.gridworks.model.Row;
public interface RowVisitor {
public boolean visit(Project project, int rowIndex, Row row, boolean contextual);
public boolean visit(
Project project,
int rowIndex, // zero-based row index
Row row,
boolean contextual, // true if this row is included because it's the context row of an included row
boolean dependent // true if this row is included because it depends on an included row
);
}

View File

@ -25,7 +25,7 @@ public class ExpressionNominalRowGrouper implements RowVisitor {
_cellIndex = cellIndex;
}
public boolean visit(Project project, int rowIndex, Row row, boolean contextual) {
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
Cell cell = _cellIndex < 0 ? null : row.getCell(_cellIndex);
Properties bindings = ExpressionUtils.createBindings(project);

View File

@ -28,7 +28,7 @@ public class ExpressionNumericRowBinner implements RowVisitor {
bins = new int[_index.getBins().length];
}
public boolean visit(Project project, int rowIndex, Row row, boolean contextual) {
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
Cell cell = row.getCell(_cellIndex);
Properties bindings = ExpressionUtils.createBindings(project);

View File

@ -62,7 +62,7 @@ public class BinningClusterer extends Clusterer {
}
}
public boolean visit(Project project, int rowIndex, Row row, boolean contextual) {
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
Cell cell = row.getCell(_colindex);
if (cell != null && cell.value != null) {
String v = cell.value.toString();

View File

@ -76,7 +76,7 @@ public class kNNClusterer extends Clusterer {
}
}
public boolean visit(Project project, int rowIndex, Row row, boolean contextual) {
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
Cell cell = row.cells.get(_colindex);
if (cell != null && cell.value != null) {
Object v = cell.value;
@ -114,7 +114,7 @@ public class kNNClusterer extends Clusterer {
}
}
public boolean visit(Project project, int rowIndex, Row row, boolean contextual) {
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
Cell cell = row.getCell(_colindex);
if (cell != null && cell.value != null) {
Object v = cell.value;

View File

@ -53,7 +53,7 @@ public class GetRowsCommand extends Command {
}
@Override
public boolean internalVisit(int rowIndex, Row row, boolean contextual) {
public boolean internalVisit(int rowIndex, Row row, boolean contextual, boolean includeDependent) {
try {
if (contextual) {
options.put("extra", extra);
@ -99,19 +99,19 @@ public class GetRowsCommand extends Command {
this.limit = limit;
}
public boolean visit(Project project, int rowIndex, Row row, boolean contextual) {
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
boolean r = false;
if (total >= start && total < start + limit) {
r = internalVisit(rowIndex, row, contextual);
r = internalVisit(rowIndex, row, includeContextual, includeDependent);
}
if (!contextual) {
if (!includeContextual) {
total++;
}
return r;
}
protected boolean internalVisit(int rowIndex, Row row, boolean contextual) {
protected boolean internalVisit(int rowIndex, Row row, boolean contextual, boolean includeDependent) {
return false;
}
}

View File

@ -38,7 +38,7 @@ public class TsvExporter implements Exporter {
return this;
}
public boolean visit(Project project, int rowIndex, Row row, boolean contextual) {
public boolean visit(Project project, int rowIndex, Row row, boolean contextual, boolean includeDependent) {
boolean first = true;
try {
for (Column column : project.columnModel.columns) {

View File

@ -246,13 +246,17 @@ public class Project {
lastNonBlankRowsByGroup[i] = -1;
}
int rowCount = rows.size();
int groupCount = keyedGroups.size();
int recordIndex = 0;
for (int r = 0; r < rows.size(); r++) {
for (int r = 0; r < rowCount; r++) {
Row row = rows.get(r);
row.contextRows = null;
row.contextRowSlots = null;
row.contextCellSlots = null;
for (int g = 0; g < keyedGroups.size(); g++) {
for (int g = 0; g < groupCount; g++) {
Group group = keyedGroups.get(g);
if (!ExpressionUtils.isNonBlankData(row.getCellValue(group.keyCellIndex))) {
@ -296,6 +300,7 @@ public class Project {
rootKeyedGroup.cellIndices = new int[count - 1];
rootKeyedGroup.keyCellIndex = columnModel.columns.get(columnModel.getKeyColumnIndex()).getCellIndex();
for (int i = 0; i < count; i++) {
if (i < rootKeyedGroup.keyCellIndex) {
rootKeyedGroup.cellIndices[i] = i;

View File

@ -121,10 +121,10 @@ public class ColumnAdditionOperation extends EngineDependentOperation {
Properties bindings = ExpressionUtils.createBindings(project);
return new RowVisitor() {
int cellIndex;
Properties bindings;
List<CellAtRow> cellsAtRows;
Evaluable eval;
int cellIndex;
Properties bindings;
List<CellAtRow> cellsAtRows;
Evaluable eval;
public RowVisitor init(int cellIndex, Properties bindings, List<CellAtRow> cellsAtRows, Evaluable eval) {
this.cellIndex = cellIndex;
@ -134,7 +134,7 @@ public class ColumnAdditionOperation extends EngineDependentOperation {
return this;
}
public boolean visit(Project project, int rowIndex, Row row, boolean contextual) {
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
Cell cell = row.getCell(cellIndex);
ExpressionUtils.bind(bindings, row, rowIndex, cell);

View File

@ -163,7 +163,7 @@ public class MassEditOperation extends EngineDependentMassCellOperation {
return this;
}
public boolean visit(Project project, int rowIndex, Row row, boolean contextual) {
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
Cell cell = row.getCell(cellIndex);
ExpressionUtils.bind(bindings, row, rowIndex, cell);

View File

@ -69,7 +69,7 @@ public class ReconDiscardJudgmentsOperation extends EngineDependentMassCellOpera
return this;
}
public boolean visit(Project project, int rowIndex, Row row, boolean contextual) {
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
Cell cell = row.getCell(cellIndex);
if (cell != null && cell.recon != null) {
Recon recon = cell.recon.dup();

View File

@ -159,7 +159,7 @@ public class ReconJudgeSimilarCellsOperation extends EngineDependentMassCellOper
return this;
}
public boolean visit(Project project, int rowIndex, Row row, boolean contextual) {
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
Cell cell = row.getCell(_cellIndex);
if (cell != null &&
ExpressionUtils.isNonBlankData(cell.value) &&

View File

@ -82,7 +82,7 @@ public class ReconMarkNewTopicsOperation extends EngineDependentMassCellOperatio
return this;
}
public boolean visit(Project project, int rowIndex, Row row, boolean contextual) {
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
Cell cell = row.getCell(cellIndex);
if (cell != null) {
Recon recon = null;

View File

@ -69,7 +69,7 @@ public class ReconMatchBestCandidatesOperation extends EngineDependentMassCellOp
return this;
}
public boolean visit(Project project, int rowIndex, Row row, boolean contextual) {
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
if (cellIndex < row.cells.size()) {
Cell cell = row.cells.get(cellIndex);
if (cell.recon != null) {

View File

@ -103,7 +103,7 @@ public class ReconMatchSpecificTopicOperation extends EngineDependentMassCellOpe
return this;
}
public boolean visit(Project project, int rowIndex, Row row, boolean contextual) {
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
if (cellIndex < row.cells.size()) {
Cell cell = row.cells.get(cellIndex);

View File

@ -170,7 +170,7 @@ public class ReconOperation extends EngineDependentOperation {
FilteredRows filteredRows = engine.getAllFilteredRows(false);
filteredRows.accept(_project, new RowVisitor() {
public boolean visit(Project project, int rowIndex, Row row, boolean contextual) {
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
if (_cellIndex < row.cells.size()) {
Cell cell = row.cells.get(_cellIndex);
if (cell != null && ExpressionUtils.isNonBlankData(cell.value)) {

View File

@ -77,7 +77,7 @@ public class RowStarOperation extends EngineDependentOperation {
return this;
}
public boolean visit(Project project, int rowIndex, Row row, boolean contextual) {
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
if (row.starred != _starred) {
RowStarChange change = new RowStarChange(rowIndex, _starred);

View File

@ -118,7 +118,7 @@ public class TextTransformOperation extends EngineDependentMassCellOperation {
return this;
}
public boolean visit(Project project, int rowIndex, Row row, boolean contextual) {
public boolean visit(Project project, int rowIndex, Row row, boolean includeContextual, boolean includeDependent) {
Cell cell = row.getCell(cellIndex);
Object oldValue = cell != null ? cell.value : null;

View File

@ -42,7 +42,10 @@ BrowsingEngine.prototype._initializeUI = function() {
this._div.html(
'<div class="browsing-panel-indicator" bind="indicator"><img src="images/small-spinner.gif" /> refreshing facets ...</div>' +
'<div class="browsing-panel-controls" bind="controls"><a href="javascript:{}" bind="refreshLink">refresh facets</a></div>' +
'<div class="browsing-panel-controls" bind="controls">' +
'<input type="checkbox" bind="includeDependentRowsCheck" /> show dependent rows &bull; ' +
'<a href="javascript:{}" bind="refreshLink">refresh</a></div>' +
'</div>' +
'<ul bind="facets" class="facets-container"></ul>'
);
this._elmts = DOM.bind(this._div);
@ -54,6 +57,10 @@ BrowsingEngine.prototype._initializeUI = function() {
});
this._elmts.facets.disableSelection();
this._elmts.includeDependentRowsCheck.change(function() {
Gridworks.update({ engineChanged: true });
});
this._elmts.refreshLink.click(function() { self.update(); });
};
@ -73,7 +80,10 @@ BrowsingEngine.prototype._updateFacetOrder = function() {
};
BrowsingEngine.prototype.getJSON = function(keepUnrestrictedFacets) {
var a = { facets: [] };
var a = {
facets: [],
includeDependent: this._elmts.includeDependentRowsCheck[0].checked
};
for (var i = 0; i < this._facets.length; i++) {
var facet = this._facets[i];
if (keepUnrestrictedFacets || facet.facet.hasSelection()) {