2010-10-20 22:45:52 +02:00
|
|
|
/*
|
|
|
|
|
|
|
|
Copyright 2010, Google Inc.
|
|
|
|
All rights reserved.
|
|
|
|
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
|
|
modification, are permitted provided that the following conditions are
|
|
|
|
met:
|
|
|
|
|
|
|
|
* Redistributions of source code must retain the above copyright
|
|
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
* Redistributions in binary form must reproduce the above
|
|
|
|
copyright notice, this list of conditions and the following disclaimer
|
|
|
|
in the documentation and/or other materials provided with the
|
|
|
|
distribution.
|
|
|
|
* Neither the name of Google Inc. nor the names of its
|
|
|
|
contributors may be used to endorse or promote products derived from
|
|
|
|
this software without specific prior written permission.
|
|
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
|
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2010-09-22 19:04:10 +02:00
|
|
|
package com.google.refine.commands.recon;
|
2010-05-05 01:24:48 +02:00
|
|
|
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.util.Properties;
|
|
|
|
|
|
|
|
import javax.servlet.ServletException;
|
|
|
|
import javax.servlet.http.HttpServletRequest;
|
|
|
|
import javax.servlet.http.HttpServletResponse;
|
|
|
|
|
|
|
|
import org.json.JSONWriter;
|
|
|
|
|
2010-09-22 19:04:10 +02:00
|
|
|
import com.google.refine.commands.Command;
|
|
|
|
import com.google.refine.expr.ExpressionUtils;
|
|
|
|
import com.google.refine.history.Change;
|
|
|
|
import com.google.refine.history.HistoryEntry;
|
|
|
|
import com.google.refine.model.Cell;
|
|
|
|
import com.google.refine.model.Column;
|
|
|
|
import com.google.refine.model.Project;
|
|
|
|
import com.google.refine.model.Recon;
|
|
|
|
import com.google.refine.model.ReconCandidate;
|
|
|
|
import com.google.refine.model.ReconStats;
|
|
|
|
import com.google.refine.model.Recon.Judgment;
|
|
|
|
import com.google.refine.model.changes.CellChange;
|
|
|
|
import com.google.refine.model.changes.ReconChange;
|
|
|
|
import com.google.refine.process.QuickHistoryEntryProcess;
|
|
|
|
import com.google.refine.util.Pool;
|
2010-05-05 01:24:48 +02:00
|
|
|
|
|
|
|
public class ReconJudgeOneCellCommand extends Command {
|
|
|
|
@Override
|
|
|
|
public void doPost(HttpServletRequest request, HttpServletResponse response)
|
|
|
|
throws ServletException, IOException {
|
2010-06-16 00:11:35 +02:00
|
|
|
|
2010-05-05 01:24:48 +02:00
|
|
|
try {
|
2010-11-27 03:46:10 +01:00
|
|
|
request.setCharacterEncoding("UTF-8");
|
|
|
|
response.setCharacterEncoding("UTF-8");
|
|
|
|
|
2010-05-05 01:24:48 +02:00
|
|
|
Project project = getProject(request);
|
2010-06-16 00:11:35 +02:00
|
|
|
|
2010-05-05 01:24:48 +02:00
|
|
|
int rowIndex = Integer.parseInt(request.getParameter("row"));
|
|
|
|
int cellIndex = Integer.parseInt(request.getParameter("cell"));
|
|
|
|
Judgment judgment = Recon.stringToJudgment(request.getParameter("judgment"));
|
2010-06-16 00:11:35 +02:00
|
|
|
|
2010-05-05 01:24:48 +02:00
|
|
|
ReconCandidate match = null;
|
2010-06-27 05:31:56 +02:00
|
|
|
String id = request.getParameter("id");
|
|
|
|
if (id != null) {
|
2010-05-05 01:24:48 +02:00
|
|
|
String scoreString = request.getParameter("score");
|
2010-06-16 00:11:35 +02:00
|
|
|
|
2010-05-05 01:24:48 +02:00
|
|
|
match = new ReconCandidate(
|
2010-06-27 05:31:56 +02:00
|
|
|
id,
|
|
|
|
request.getParameter("name"),
|
2010-05-05 01:24:48 +02:00
|
|
|
request.getParameter("types").split(","),
|
|
|
|
scoreString != null ? Double.parseDouble(scoreString) : 100
|
|
|
|
);
|
|
|
|
}
|
2010-06-16 00:11:35 +02:00
|
|
|
|
2010-05-05 01:24:48 +02:00
|
|
|
JudgeOneCellProcess process = new JudgeOneCellProcess(
|
2010-06-16 00:11:35 +02:00
|
|
|
project,
|
2010-05-05 01:24:48 +02:00
|
|
|
"Judge one cell's recon result",
|
|
|
|
judgment,
|
2010-06-16 00:11:35 +02:00
|
|
|
rowIndex,
|
|
|
|
cellIndex,
|
2010-06-24 22:13:51 +02:00
|
|
|
match,
|
|
|
|
request.getParameter("identifierSpace"),
|
|
|
|
request.getParameter("schemaSpace")
|
2010-05-05 01:24:48 +02:00
|
|
|
);
|
2010-06-16 00:11:35 +02:00
|
|
|
|
2010-05-05 01:24:48 +02:00
|
|
|
HistoryEntry historyEntry = project.processManager.queueProcess(process);
|
|
|
|
if (historyEntry != null) {
|
|
|
|
/*
|
|
|
|
* If the process is done, write back the cell's data so that the
|
|
|
|
* client side can update its UI right away.
|
|
|
|
*/
|
|
|
|
JSONWriter writer = new JSONWriter(response.getWriter());
|
2010-06-16 00:11:35 +02:00
|
|
|
|
2010-05-05 01:24:48 +02:00
|
|
|
Pool pool = new Pool();
|
|
|
|
Properties options = new Properties();
|
|
|
|
options.put("pool", pool);
|
2010-06-16 00:11:35 +02:00
|
|
|
|
2010-05-05 01:24:48 +02:00
|
|
|
writer.object();
|
|
|
|
writer.key("code"); writer.value("ok");
|
|
|
|
writer.key("historyEntry"); historyEntry.write(writer, options);
|
|
|
|
writer.key("cell"); process.newCell.write(writer, options);
|
|
|
|
writer.key("pool"); pool.write(writer, options);
|
|
|
|
writer.endObject();
|
|
|
|
} else {
|
|
|
|
respond(response, "{ \"code\" : \"pending\" }");
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
respondException(response, e);
|
|
|
|
}
|
|
|
|
}
|
2010-06-16 00:11:35 +02:00
|
|
|
|
2010-05-05 01:24:48 +02:00
|
|
|
protected static class JudgeOneCellProcess extends QuickHistoryEntryProcess {
|
|
|
|
|
2010-06-24 22:13:51 +02:00
|
|
|
final int rowIndex;
|
|
|
|
final int cellIndex;
|
|
|
|
final Judgment judgment;
|
|
|
|
final ReconCandidate match;
|
|
|
|
final String identifierSpace;
|
|
|
|
final String schemaSpace;
|
|
|
|
|
2010-05-05 01:24:48 +02:00
|
|
|
Cell newCell;
|
2010-06-16 00:11:35 +02:00
|
|
|
|
2010-05-05 01:24:48 +02:00
|
|
|
JudgeOneCellProcess(
|
2010-06-16 00:11:35 +02:00
|
|
|
Project project,
|
|
|
|
String briefDescription,
|
|
|
|
Judgment judgment,
|
|
|
|
int rowIndex,
|
|
|
|
int cellIndex,
|
2010-06-24 22:13:51 +02:00
|
|
|
ReconCandidate match,
|
|
|
|
String identifierSpace,
|
|
|
|
String schemaSpace
|
2010-05-05 01:24:48 +02:00
|
|
|
) {
|
|
|
|
super(project, briefDescription);
|
2010-06-16 00:11:35 +02:00
|
|
|
|
2010-05-05 01:24:48 +02:00
|
|
|
this.judgment = judgment;
|
|
|
|
this.rowIndex = rowIndex;
|
|
|
|
this.cellIndex = cellIndex;
|
|
|
|
this.match = match;
|
2010-06-24 22:13:51 +02:00
|
|
|
this.identifierSpace = identifierSpace;
|
|
|
|
this.schemaSpace = schemaSpace;
|
2010-05-05 01:24:48 +02:00
|
|
|
}
|
|
|
|
|
2011-08-02 21:30:23 +02:00
|
|
|
@Override
|
2010-05-05 01:24:48 +02:00
|
|
|
protected HistoryEntry createHistoryEntry(long historyEntryID) throws Exception {
|
|
|
|
Cell cell = _project.rows.get(rowIndex).getCell(cellIndex);
|
|
|
|
if (cell == null || !ExpressionUtils.isNonBlankData(cell.value)) {
|
|
|
|
throw new Exception("Cell is blank or error");
|
|
|
|
}
|
2010-06-16 00:11:35 +02:00
|
|
|
|
2010-05-05 01:24:48 +02:00
|
|
|
Column column = _project.columnModel.getColumnByCellIndex(cellIndex);
|
|
|
|
if (column == null) {
|
|
|
|
throw new Exception("No such column");
|
|
|
|
}
|
2010-06-16 00:11:35 +02:00
|
|
|
|
2010-05-05 01:24:48 +02:00
|
|
|
Judgment oldJudgment = cell.recon == null ? Judgment.None : cell.recon.judgment;
|
2010-06-16 00:11:35 +02:00
|
|
|
|
2010-05-05 01:24:48 +02:00
|
|
|
newCell = new Cell(
|
2010-06-16 00:11:35 +02:00
|
|
|
cell.value,
|
2010-06-24 22:13:51 +02:00
|
|
|
cell.recon == null ? new Recon(historyEntryID, identifierSpace, schemaSpace) : cell.recon.dup(historyEntryID)
|
2010-05-05 01:24:48 +02:00
|
|
|
);
|
2010-06-16 00:11:35 +02:00
|
|
|
|
|
|
|
String cellDescription =
|
|
|
|
"single cell on row " + (rowIndex + 1) +
|
|
|
|
", column " + column.getName() +
|
2010-05-05 01:24:48 +02:00
|
|
|
", containing \"" + cell.value + "\"";
|
2010-06-16 00:11:35 +02:00
|
|
|
|
2010-05-05 01:24:48 +02:00
|
|
|
String description = null;
|
2010-06-16 00:11:35 +02:00
|
|
|
|
2010-05-05 01:24:48 +02:00
|
|
|
newCell.recon.matchRank = -1;
|
|
|
|
newCell.recon.judgmentAction = "single";
|
|
|
|
newCell.recon.judgmentBatchSize = 1;
|
2010-06-16 00:11:35 +02:00
|
|
|
|
2010-05-05 01:24:48 +02:00
|
|
|
if (judgment == Judgment.None) {
|
|
|
|
newCell.recon.judgment = Recon.Judgment.None;
|
|
|
|
newCell.recon.match = null;
|
2010-06-16 00:11:35 +02:00
|
|
|
|
2010-05-05 01:24:48 +02:00
|
|
|
description = "Discard recon judgment for " + cellDescription;
|
|
|
|
} else if (judgment == Judgment.New) {
|
|
|
|
newCell.recon.judgment = Recon.Judgment.New;
|
|
|
|
newCell.recon.match = null;
|
2010-06-16 00:11:35 +02:00
|
|
|
|
2010-05-05 01:24:48 +02:00
|
|
|
description = "Mark to create new topic for " + cellDescription;
|
|
|
|
} else {
|
|
|
|
newCell.recon.judgment = Recon.Judgment.Matched;
|
|
|
|
newCell.recon.match = this.match;
|
2010-06-24 22:13:51 +02:00
|
|
|
if (newCell.recon.candidates != null) {
|
|
|
|
for (int m = 0; m < newCell.recon.candidates.size(); m++) {
|
|
|
|
if (newCell.recon.candidates.get(m).id.equals(this.match.id)) {
|
|
|
|
newCell.recon.matchRank = m;
|
|
|
|
break;
|
|
|
|
}
|
2010-05-05 01:24:48 +02:00
|
|
|
}
|
|
|
|
}
|
2010-06-24 22:13:51 +02:00
|
|
|
|
|
|
|
description = "Match " + this.match.name +
|
|
|
|
" (" + match.id + ") to " +
|
2010-05-05 01:24:48 +02:00
|
|
|
cellDescription;
|
|
|
|
}
|
2010-06-16 00:11:35 +02:00
|
|
|
|
2010-05-05 01:24:48 +02:00
|
|
|
ReconStats stats = column.getReconStats();
|
|
|
|
if (stats == null) {
|
|
|
|
stats = ReconStats.create(_project, cellIndex);
|
|
|
|
} else {
|
|
|
|
int newChange = 0;
|
|
|
|
int matchChange = 0;
|
2010-06-16 00:11:35 +02:00
|
|
|
|
2010-05-05 01:24:48 +02:00
|
|
|
if (oldJudgment == Judgment.New) {
|
|
|
|
newChange--;
|
|
|
|
}
|
|
|
|
if (oldJudgment == Judgment.Matched) {
|
|
|
|
matchChange--;
|
|
|
|
}
|
|
|
|
if (newCell.recon.judgment == Judgment.New) {
|
|
|
|
newChange++;
|
|
|
|
}
|
|
|
|
if (newCell.recon.judgment == Judgment.Matched) {
|
|
|
|
matchChange++;
|
|
|
|
}
|
2010-06-16 00:11:35 +02:00
|
|
|
|
2010-05-05 01:24:48 +02:00
|
|
|
stats = new ReconStats(
|
2010-06-16 00:11:35 +02:00
|
|
|
stats.nonBlanks,
|
|
|
|
stats.newTopics + newChange,
|
2010-05-05 01:24:48 +02:00
|
|
|
stats.matchedTopics + matchChange);
|
|
|
|
}
|
2010-06-16 00:11:35 +02:00
|
|
|
|
2010-05-05 01:24:48 +02:00
|
|
|
Change change = new ReconChange(
|
2010-06-16 00:11:35 +02:00
|
|
|
new CellChange(rowIndex, cellIndex, cell, newCell),
|
|
|
|
column.getName(),
|
2010-05-05 01:24:48 +02:00
|
|
|
column.getReconConfig(),
|
|
|
|
stats
|
|
|
|
);
|
2010-06-16 00:11:35 +02:00
|
|
|
|
2010-06-16 14:35:37 +02:00
|
|
|
return new HistoryEntry(
|
2010-05-05 01:24:48 +02:00
|
|
|
historyEntryID, _project, description, null, change);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|