From 6889d0e58ac11547b55d24f3e921e045c0718b17 Mon Sep 17 00:00:00 2001 From: David Huynh Date: Wed, 27 Jan 2010 07:52:05 +0000 Subject: [PATCH] Server-side scaffolding for faceted browsing. git-svn-id: http://google-refine.googlecode.com/svn/trunk@9 7d457c2a-affb-35e4-300a-418c747d4874 --- .../browsing/ConjunctiveFilteredRows.java | 33 +++++++++ .../com/metaweb/gridlock/browsing/Engine.java | 71 +++++++++++++++++++ .../gridlock/browsing/FilteredRows.java | 7 ++ .../metaweb/gridlock/browsing/RowVisitor.java | 8 +++ .../browsing/accessors/CellAccessor.java | 7 ++ .../accessors/ReconFeatureCellAccessor.java | 19 +++++ .../browsing/accessors/ReconTypeAccessor.java | 15 ++++ .../browsing/accessors/ValueCellAccessor.java | 13 ++++ .../facets/CellAccessorNominalRowGrouper.java | 46 ++++++++++++ .../gridlock/browsing/facets/Facet.java | 19 +++++ .../gridlock/browsing/facets/ListFacet.java | 30 ++++++++ .../browsing/facets/NominalFacetChoice.java | 6 ++ .../filters/CellAccessorEqualRowFilter.java | 37 ++++++++++ .../gridlock/browsing/filters/RowFilter.java | 7 ++ 14 files changed, 318 insertions(+) create mode 100644 src/main/java/com/metaweb/gridlock/browsing/ConjunctiveFilteredRows.java create mode 100644 src/main/java/com/metaweb/gridlock/browsing/Engine.java create mode 100644 src/main/java/com/metaweb/gridlock/browsing/FilteredRows.java create mode 100644 src/main/java/com/metaweb/gridlock/browsing/RowVisitor.java create mode 100644 src/main/java/com/metaweb/gridlock/browsing/accessors/CellAccessor.java create mode 100644 src/main/java/com/metaweb/gridlock/browsing/accessors/ReconFeatureCellAccessor.java create mode 100644 src/main/java/com/metaweb/gridlock/browsing/accessors/ReconTypeAccessor.java create mode 100644 src/main/java/com/metaweb/gridlock/browsing/accessors/ValueCellAccessor.java create mode 100644 src/main/java/com/metaweb/gridlock/browsing/facets/CellAccessorNominalRowGrouper.java create mode 100644 src/main/java/com/metaweb/gridlock/browsing/facets/Facet.java create mode 100644 src/main/java/com/metaweb/gridlock/browsing/facets/ListFacet.java create mode 100644 src/main/java/com/metaweb/gridlock/browsing/facets/NominalFacetChoice.java create mode 100644 src/main/java/com/metaweb/gridlock/browsing/filters/CellAccessorEqualRowFilter.java create mode 100644 src/main/java/com/metaweb/gridlock/browsing/filters/RowFilter.java diff --git a/src/main/java/com/metaweb/gridlock/browsing/ConjunctiveFilteredRows.java b/src/main/java/com/metaweb/gridlock/browsing/ConjunctiveFilteredRows.java new file mode 100644 index 000000000..b2ebdb77d --- /dev/null +++ b/src/main/java/com/metaweb/gridlock/browsing/ConjunctiveFilteredRows.java @@ -0,0 +1,33 @@ +package com.metaweb.gridlock.browsing; + +import java.util.LinkedList; +import java.util.List; + +import com.metaweb.gridlock.browsing.filters.RowFilter; +import com.metaweb.gridlock.model.Project; +import com.metaweb.gridlock.model.Row; + +public class ConjunctiveFilteredRows implements FilteredRows { + final protected List _rowFilters = new LinkedList(); + + public void add(RowFilter rowFilter) { + _rowFilters.add(rowFilter); + } + + @Override + public void accept(Project project, RowVisitor visitor) { + for (Row row : project.rows) { + boolean ok = true; + for (RowFilter rowFilter : _rowFilters) { + if (!rowFilter.filterRow(row)) { + ok = false; + break; + } + } + + if (ok) { + visitor.visit(row); + } + } + } +} diff --git a/src/main/java/com/metaweb/gridlock/browsing/Engine.java b/src/main/java/com/metaweb/gridlock/browsing/Engine.java new file mode 100644 index 000000000..6a2604218 --- /dev/null +++ b/src/main/java/com/metaweb/gridlock/browsing/Engine.java @@ -0,0 +1,71 @@ +package com.metaweb.gridlock.browsing; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Properties; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import com.metaweb.gridlock.browsing.facets.Facet; +import com.metaweb.gridlock.browsing.facets.ListFacet; + +public class Engine { + protected List facets = new LinkedList(); + + public FilteredRows getAllFilteredRows() { + return getFilteredRows(null); + } + + public FilteredRows getFilteredRows(Facet except) { + ConjunctiveFilteredRows cfr = new ConjunctiveFilteredRows(); + for (Facet facet : facets) { + if (facet != except) { + cfr.add(facet.getRowFilter()); + } + } + return cfr; + } + + public JSONObject getJSON(Properties options) throws JSONException { + JSONObject o = new JSONObject(); + + List a = new ArrayList(facets.size()); + for (Facet facet : facets) { + a.add(facet.getJSON(options)); + } + o.put("facets", a); + + return o; + } + + public void initializeFromJSON(JSONObject o) throws JSONException { + JSONArray a = o.getJSONArray("facets"); + int length = a.length(); + + for (int i = 0; i < length; i++) { + JSONObject fo = a.getJSONObject(i); + String type = fo.getString("type"); + + Facet facet = null; + if ("list".equals(type)) { + facet = new ListFacet(); + } + + if (facet != null) { + facet.initializeFromJSON(fo); + facets.add(facet); + } + } + } + + public void computeFacets() throws JSONException { + for (Facet facet : facets) { + FilteredRows filteredRows = getFilteredRows(facet); + + facet.computeChoices(filteredRows); + } + } +} diff --git a/src/main/java/com/metaweb/gridlock/browsing/FilteredRows.java b/src/main/java/com/metaweb/gridlock/browsing/FilteredRows.java new file mode 100644 index 000000000..a802bb2d4 --- /dev/null +++ b/src/main/java/com/metaweb/gridlock/browsing/FilteredRows.java @@ -0,0 +1,7 @@ +package com.metaweb.gridlock.browsing; + +import com.metaweb.gridlock.model.Project; + +public interface FilteredRows { + public void accept(Project project, RowVisitor visitor); +} diff --git a/src/main/java/com/metaweb/gridlock/browsing/RowVisitor.java b/src/main/java/com/metaweb/gridlock/browsing/RowVisitor.java new file mode 100644 index 000000000..e69b881ac --- /dev/null +++ b/src/main/java/com/metaweb/gridlock/browsing/RowVisitor.java @@ -0,0 +1,8 @@ +package com.metaweb.gridlock.browsing; + +import com.metaweb.gridlock.model.Row; + +public interface RowVisitor { + public void visit(Row row); + +} diff --git a/src/main/java/com/metaweb/gridlock/browsing/accessors/CellAccessor.java b/src/main/java/com/metaweb/gridlock/browsing/accessors/CellAccessor.java new file mode 100644 index 000000000..4f5c66fe6 --- /dev/null +++ b/src/main/java/com/metaweb/gridlock/browsing/accessors/CellAccessor.java @@ -0,0 +1,7 @@ +package com.metaweb.gridlock.browsing.accessors; + +import com.metaweb.gridlock.model.Cell; + +public interface CellAccessor { + public Object[] get(Cell cell); +} diff --git a/src/main/java/com/metaweb/gridlock/browsing/accessors/ReconFeatureCellAccessor.java b/src/main/java/com/metaweb/gridlock/browsing/accessors/ReconFeatureCellAccessor.java new file mode 100644 index 000000000..085509f99 --- /dev/null +++ b/src/main/java/com/metaweb/gridlock/browsing/accessors/ReconFeatureCellAccessor.java @@ -0,0 +1,19 @@ +package com.metaweb.gridlock.browsing.accessors; + +import com.metaweb.gridlock.model.Cell; + +public class ReconFeatureCellAccessor implements CellAccessor { + final protected String _name; + + public ReconFeatureCellAccessor(String name) { + _name = name; + } + + @Override + public Object[] get(Cell cell) { + if (cell.recon != null) { + return new Object[] { cell.recon.features.get(_name) }; + } + return null; + } +} diff --git a/src/main/java/com/metaweb/gridlock/browsing/accessors/ReconTypeAccessor.java b/src/main/java/com/metaweb/gridlock/browsing/accessors/ReconTypeAccessor.java new file mode 100644 index 000000000..9d64318a3 --- /dev/null +++ b/src/main/java/com/metaweb/gridlock/browsing/accessors/ReconTypeAccessor.java @@ -0,0 +1,15 @@ +package com.metaweb.gridlock.browsing.accessors; + +import com.metaweb.gridlock.model.Cell; +import com.metaweb.gridlock.model.ReconCandidate; + +public class ReconTypeAccessor implements CellAccessor { + @Override + public Object[] get(Cell cell) { + if (cell.recon != null && cell.recon.candidates.size() > 0) { + ReconCandidate c = cell.recon.candidates.get(0); + return c.typeIDs; + } + return null; + } +} diff --git a/src/main/java/com/metaweb/gridlock/browsing/accessors/ValueCellAccessor.java b/src/main/java/com/metaweb/gridlock/browsing/accessors/ValueCellAccessor.java new file mode 100644 index 000000000..c3816be8a --- /dev/null +++ b/src/main/java/com/metaweb/gridlock/browsing/accessors/ValueCellAccessor.java @@ -0,0 +1,13 @@ +package com.metaweb.gridlock.browsing.accessors; + +import com.metaweb.gridlock.model.Cell; + +public class ValueCellAccessor implements CellAccessor { + @Override + public Object[] get(Cell cell) { + if (cell.value != null) { + return new Object[] { cell.value }; + } + return null; + } +} diff --git a/src/main/java/com/metaweb/gridlock/browsing/facets/CellAccessorNominalRowGrouper.java b/src/main/java/com/metaweb/gridlock/browsing/facets/CellAccessorNominalRowGrouper.java new file mode 100644 index 000000000..ce0145fe1 --- /dev/null +++ b/src/main/java/com/metaweb/gridlock/browsing/facets/CellAccessorNominalRowGrouper.java @@ -0,0 +1,46 @@ +package com.metaweb.gridlock.browsing.facets; + +import java.util.HashMap; +import java.util.Map; + +import com.metaweb.gridlock.browsing.RowVisitor; +import com.metaweb.gridlock.browsing.accessors.CellAccessor; +import com.metaweb.gridlock.model.Cell; +import com.metaweb.gridlock.model.Row; + +public class CellAccessorNominalRowGrouper implements RowVisitor { + final protected CellAccessor _accessor; + final protected int _cellIndex; + + final public Map groups = new HashMap(); + + public CellAccessorNominalRowGrouper(CellAccessor accessor, int cellIndex) { + _accessor = accessor; + _cellIndex = cellIndex; + } + + @Override + public void visit(Row row) { + if (_cellIndex < row.cells.size()) { + Cell cell = row.cells.get(_cellIndex); + if (cell != null) { + Object[] values = _accessor.get(cell); + if (values != null && values.length > 0) { + for (Object v : values) { + if (v != null) { + if (groups.containsKey(v)) { + groups.get(v).count++; + } else { + NominalFacetChoice group = new NominalFacetChoice(); + group.value = v; + group.count = 1; + + groups.put(v, group); + } + } + } + } + } + } + } +} diff --git a/src/main/java/com/metaweb/gridlock/browsing/facets/Facet.java b/src/main/java/com/metaweb/gridlock/browsing/facets/Facet.java new file mode 100644 index 000000000..d786dc1c9 --- /dev/null +++ b/src/main/java/com/metaweb/gridlock/browsing/facets/Facet.java @@ -0,0 +1,19 @@ +package com.metaweb.gridlock.browsing.facets; + +import java.util.Properties; + +import org.json.JSONException; +import org.json.JSONObject; + +import com.metaweb.gridlock.browsing.FilteredRows; +import com.metaweb.gridlock.browsing.filters.RowFilter; + +public interface Facet { + public RowFilter getRowFilter(); + + public void computeChoices(FilteredRows filteredRows); + + public JSONObject getJSON(Properties options) throws JSONException; + + public void initializeFromJSON(JSONObject o) throws JSONException; +} diff --git a/src/main/java/com/metaweb/gridlock/browsing/facets/ListFacet.java b/src/main/java/com/metaweb/gridlock/browsing/facets/ListFacet.java new file mode 100644 index 000000000..95eb637eb --- /dev/null +++ b/src/main/java/com/metaweb/gridlock/browsing/facets/ListFacet.java @@ -0,0 +1,30 @@ +package com.metaweb.gridlock.browsing.facets; + +import java.util.Properties; + +import org.json.JSONException; +import org.json.JSONObject; + +import com.metaweb.gridlock.browsing.filters.RowFilter; + +public class ListFacet implements Facet { + + @Override + public JSONObject getJSON(Properties options) throws JSONException { + // TODO Auto-generated method stub + return null; + } + + @Override + public RowFilter getRowFilter() { + // TODO Auto-generated method stub + return null; + } + + @Override + public void initializeFromJSON(JSONObject o) throws JSONException { + // TODO Auto-generated method stub + + } + +} diff --git a/src/main/java/com/metaweb/gridlock/browsing/facets/NominalFacetChoice.java b/src/main/java/com/metaweb/gridlock/browsing/facets/NominalFacetChoice.java new file mode 100644 index 000000000..18e71ab60 --- /dev/null +++ b/src/main/java/com/metaweb/gridlock/browsing/facets/NominalFacetChoice.java @@ -0,0 +1,6 @@ +package com.metaweb.gridlock.browsing.facets; + +public class NominalFacetChoice { + public Object value; + public int count; +} diff --git a/src/main/java/com/metaweb/gridlock/browsing/filters/CellAccessorEqualRowFilter.java b/src/main/java/com/metaweb/gridlock/browsing/filters/CellAccessorEqualRowFilter.java new file mode 100644 index 000000000..267b8190a --- /dev/null +++ b/src/main/java/com/metaweb/gridlock/browsing/filters/CellAccessorEqualRowFilter.java @@ -0,0 +1,37 @@ +package com.metaweb.gridlock.browsing.filters; + +import com.metaweb.gridlock.browsing.accessors.CellAccessor; +import com.metaweb.gridlock.model.Cell; +import com.metaweb.gridlock.model.Row; + +public class CellAccessorEqualRowFilter implements RowFilter { + final protected CellAccessor _accessor; + final protected int _cellIndex; + final protected Object[] _matches; + + public CellAccessorEqualRowFilter(CellAccessor accessor, int cellIndex, Object[] matches) { + _accessor = accessor; + _cellIndex = cellIndex; + _matches = matches; + } + + @Override + public boolean filterRow(Row row) { + if (_cellIndex < row.cells.size()) { + Cell cell = row.cells.get(_cellIndex); + if (cell != null) { + Object[] values = _accessor.get(cell); + if (values != null && values.length > 0) { + for (Object v : values) { + for (Object match : _matches) { + if (match.equals(v)) { + return true; + } + } + } + } + } + } + return false; + } +} diff --git a/src/main/java/com/metaweb/gridlock/browsing/filters/RowFilter.java b/src/main/java/com/metaweb/gridlock/browsing/filters/RowFilter.java new file mode 100644 index 000000000..762369ae2 --- /dev/null +++ b/src/main/java/com/metaweb/gridlock/browsing/filters/RowFilter.java @@ -0,0 +1,7 @@ +package com.metaweb.gridlock.browsing.filters; + +import com.metaweb.gridlock.model.Row; + +public interface RowFilter { + public boolean filterRow(Row row); +}