Use the schema index to suggest properties in the schema alignment dialog.
Fixed minor bug in triple loader transposer that wrote a bad triple for each literal cell value. git-svn-id: http://google-refine.googlecode.com/svn/trunk@112 7d457c2a-affb-35e4-300a-418c747d4874
This commit is contained in:
parent
c4396798e3
commit
ea2c904704
@ -151,6 +151,7 @@ public class TripleLoaderTransposedNodeFactory implements TransposedNodeFactory
|
|||||||
String object = cell.value instanceof String ?
|
String object = cell.value instanceof String ?
|
||||||
JSONObject.quote((String) cell.value) : cell.value.toString();
|
JSONObject.quote((String) cell.value) : cell.value.toString();
|
||||||
|
|
||||||
|
if (subject != null) {
|
||||||
if ("/type/text".equals(node.lang)) {
|
if ("/type/text".equals(node.lang)) {
|
||||||
writeLine(
|
writeLine(
|
||||||
"{ 's' : '" + subject +
|
"{ 's' : '" + subject +
|
||||||
@ -166,6 +167,7 @@ public class TripleLoaderTransposedNodeFactory implements TransposedNodeFactory
|
|||||||
"', 'o' : " + object + " }"
|
"', 'o' : " + object + " }"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,17 @@ MenuBar.prototype._initializeUI = function() {
|
|||||||
click: function() { self._doAutoSchemaAlignment(); }
|
click: function() { self._doAutoSchemaAlignment(); }
|
||||||
},*/
|
},*/
|
||||||
{
|
{
|
||||||
label: "Edit Schema Alignment ...",
|
label: "Edit Schema Aligment Skeleton ...",
|
||||||
click: function() { self._doEditSchemaAlignment(); }
|
click: function() { self._doEditSchemaAlignment(false); }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Reset Schema Alignment Skeleton ...",
|
||||||
|
click: function() { self._doEditSchemaAlignment(true); }
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
label: "Load into Freebase ...",
|
||||||
|
click: function() {}
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -139,6 +148,6 @@ MenuBar.prototype._doAutoSchemaAlignment = function() {
|
|||||||
//SchemaAlignment.autoAlign();
|
//SchemaAlignment.autoAlign();
|
||||||
};
|
};
|
||||||
|
|
||||||
MenuBar.prototype._doEditSchemaAlignment = function() {
|
MenuBar.prototype._doEditSchemaAlignment = function(reset) {
|
||||||
new SchemaAlignmentDialog(theProject.protograph, function(newProtograph) {});
|
new SchemaAlignmentDialog(reset ? null : theProject.protograph, function(newProtograph) {});
|
||||||
};
|
};
|
||||||
|
@ -67,7 +67,7 @@ SchemaAlignmentDialog.UILink.prototype._renderMain = function() {
|
|||||||
.html(label)
|
.html(label)
|
||||||
.appendTo(this._tdMain)
|
.appendTo(this._tdMain)
|
||||||
.click(function(evt) {
|
.click(function(evt) {
|
||||||
self._showPropertySuggestPopup(this);
|
self._startEditProperty(this);
|
||||||
});
|
});
|
||||||
|
|
||||||
$('<img />').attr("src", "images/arrow-start.png").prependTo(a);
|
$('<img />').attr("src", "images/arrow-start.png").prependTo(a);
|
||||||
@ -75,51 +75,247 @@ SchemaAlignmentDialog.UILink.prototype._renderMain = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
SchemaAlignmentDialog.UILink.prototype._renderDetails = function() {
|
SchemaAlignmentDialog.UILink.prototype._renderDetails = function() {
|
||||||
var tableDetails = $('<table></table>').addClass("schema-alignment-table-layout").appendTo(this._expandedDetailDiv)[0];
|
if (this._targetUI) {
|
||||||
|
this._targetUI.dispose();
|
||||||
|
}
|
||||||
|
if (this._tableDetails) {
|
||||||
|
this._tableDetails.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
this._tableDetails = $('<table></table>').addClass("schema-alignment-table-layout").appendTo(this._expandedDetailDiv);
|
||||||
this._targetUI = new SchemaAlignmentDialog.UINode(
|
this._targetUI = new SchemaAlignmentDialog.UINode(
|
||||||
this._dialog,
|
this._dialog,
|
||||||
this._link.target,
|
this._link.target,
|
||||||
tableDetails,
|
this._tableDetails[0],
|
||||||
{ expanded: "links" in this._link.target && this._link.target.links.length > 0 });
|
{ expanded: "links" in this._link.target && this._link.target.links.length > 0 });
|
||||||
};
|
};
|
||||||
|
|
||||||
SchemaAlignmentDialog.UILink.prototype._showPropertySuggestPopup = function(elmt) {
|
SchemaAlignmentDialog.UILink.prototype._startEditProperty = function(elmt) {
|
||||||
self = this;
|
var sourceTypeID = this._parentUINode.getExpectedType();
|
||||||
|
var targetTypeID = "type" in this._link.target && this._link.target.type != null ? this._link.target.type.id : null;
|
||||||
|
var targetTypeName = "columnName" in this._link.target ? this._link.target.columnName : null;
|
||||||
|
|
||||||
var fakeMenu = MenuSystem.createMenu()
|
if (sourceTypeID != null) {
|
||||||
.width(300)
|
var self = this;
|
||||||
.height(100)
|
var dismissBusy = DialogSystem.showBusy();
|
||||||
.css("background", "none")
|
|
||||||
.css("border", "none");
|
|
||||||
|
|
||||||
var input = $('<input />').appendTo(fakeMenu);
|
var instanceCount = 0;
|
||||||
|
var outgoing = [];
|
||||||
|
var incoming = [];
|
||||||
|
|
||||||
var level = MenuSystem.showMenu(fakeMenu, function(){});
|
function onDone() {
|
||||||
MenuSystem.positionMenuAboveBelow(fakeMenu, $(elmt));
|
dismissBusy();
|
||||||
|
|
||||||
var options = {
|
var suggestions = SchemaAlignmentDialog.UILink._rankProperties(outgoing, incoming, sourceTypeID, targetTypeID, targetTypeName);
|
||||||
type : '/type/property'
|
self._showPropertySuggestPopup(elmt, suggestions);
|
||||||
};
|
};
|
||||||
var expectedTypeID = this._parentUINode.getExpectedType();
|
|
||||||
if (expectedTypeID != null) {
|
var cotypes = [];
|
||||||
options.mql_filter = [{
|
function doCoTypes() {
|
||||||
"/type/property/schema" : { "id" : expectedTypeID }
|
if (cotypes.length === 0) {
|
||||||
}];
|
onDone();
|
||||||
|
} else {
|
||||||
|
var cotype = cotypes.pop();
|
||||||
|
SchemaAlignmentDialog.UILink._getPropertiesOfType(
|
||||||
|
cotype.t,
|
||||||
|
outgoing,
|
||||||
|
incoming,
|
||||||
|
cotype.c / instanceCount,
|
||||||
|
doCoTypes
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SchemaAlignmentDialog.UILink._getPropertiesOfType(
|
||||||
|
sourceTypeID,
|
||||||
|
outgoing,
|
||||||
|
incoming,
|
||||||
|
1,
|
||||||
|
function(data) {
|
||||||
|
if ("result" in data) {
|
||||||
|
instanceCount = data.result.count;
|
||||||
|
if ("cotypes" in data.result) {
|
||||||
|
cotypes = data.result.cotypes.slice(0, 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
doCoTypes();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this._showPropertySuggestPopup(elmt, []);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SchemaAlignmentDialog.UILink._rankProperties = function(outgoing, incoming, sourceTypeID, targetTypeID, targetTypeName) {
|
||||||
|
var nameScorer;
|
||||||
|
if (targetTypeName === null) {
|
||||||
|
nameScorer = function() { return 1; };
|
||||||
|
} else {
|
||||||
|
var nameWords = targetTypeName.toLowerCase().replace(/\W/g, ' ').replace(/\s+/g, ' ').split(" ");
|
||||||
|
var nameScoreString = function(score, s) {
|
||||||
|
s = s.toLowerCase().replace(/\W/g, ' ');
|
||||||
|
|
||||||
|
var n = 0;
|
||||||
|
for (var i = 0; i < nameWords.length; i++) {
|
||||||
|
if (s.indexOf(nameWords[i]) >= 0) {
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Math.max(score, n / nameWords.length);
|
||||||
|
};
|
||||||
|
var nameScoreStrings = function(score, a) {
|
||||||
|
$.each(a, function() { score = nameScoreString(score, this); });
|
||||||
|
return score;
|
||||||
|
};
|
||||||
|
|
||||||
|
nameScorer = function(p) {
|
||||||
|
var score = nameScoreString(0, p.name);
|
||||||
|
score = nameScoreStrings(score, p.alias);
|
||||||
|
|
||||||
|
if ("expects" in p && p.expects !== null) {
|
||||||
|
score = nameScoreString(score, p.expects.name);
|
||||||
|
score = nameScoreStrings(score, p.expects.alias);
|
||||||
|
if ("plural_names" in p.expects) {
|
||||||
|
score = nameScoreStrings(score, p.expects.plural_names);
|
||||||
|
}
|
||||||
|
if ("plural_aliases" in p.expects) {
|
||||||
|
score = nameScoreStrings(score, p.expects.plural_aliases);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
input.suggest(options).bind("fb-select", function(e, data) {
|
return score;
|
||||||
self._link.property = {
|
};
|
||||||
id: data.id,
|
|
||||||
name: data.name
|
|
||||||
};
|
};
|
||||||
self._configureTarget();
|
|
||||||
|
|
||||||
window.setTimeout(function() {
|
var typeScorer;
|
||||||
MenuSystem.dismissAll();
|
if (targetTypeID === null) {
|
||||||
self._renderMain();
|
typeScorer = function(p) { return p.weight; };
|
||||||
self._dialog.preview();
|
} else {
|
||||||
}, 100);
|
typeScorer = function(p) {
|
||||||
|
return p.expects.id == targetTypeID ? 1 : p.weight;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var suggestions = [];
|
||||||
|
for (var i = 0; i < outgoing.length; i++) {
|
||||||
|
var p = outgoing[i];
|
||||||
|
p.score = p.weight * (0.5 * nameScorer(p) + 0.5 * typeScorer(p));
|
||||||
|
if (p.score > 0) {
|
||||||
|
suggestions.push(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suggestions.sort(function(a, b) { return b.score - a.score; });
|
||||||
|
suggestions = suggestions.slice(0, 7);
|
||||||
|
|
||||||
|
return suggestions;
|
||||||
|
};
|
||||||
|
|
||||||
|
SchemaAlignmentDialog.UILink._getPropertiesOfType = function(typeID, outgoing, incoming, weight, onDone) {
|
||||||
|
$.getJSON(
|
||||||
|
"http://api.sandbox-freebase.com/api/trans/schema_index/-" + typeID + "?callback=?",
|
||||||
|
null,
|
||||||
|
function(data) {
|
||||||
|
if ("result" in data) {
|
||||||
|
var result = data.result;
|
||||||
|
if ("outgoing" in result) {
|
||||||
|
for (var i = 0; i < result.outgoing.length; i++) {
|
||||||
|
var p = result.outgoing[i];
|
||||||
|
p.weight = weight;
|
||||||
|
outgoing.push(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ("incoming" in result) {
|
||||||
|
for (var i = 0; i < result.incoming.length; i++) {
|
||||||
|
var p = result.incoming[i];
|
||||||
|
p.weight = weight;
|
||||||
|
incoming.push(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onDone(data);
|
||||||
|
},
|
||||||
|
"jsonp"
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
SchemaAlignmentDialog.UILink.prototype._showPropertySuggestPopup = function(elmt, suggestions) {
|
||||||
|
self = this;
|
||||||
|
|
||||||
|
var menu = MenuSystem.createMenu().width("350px");
|
||||||
|
|
||||||
|
var commitProperty = function(p) {
|
||||||
|
window.setTimeout(function() { MenuSystem.dismissAll(); }, 100);
|
||||||
|
|
||||||
|
if ("plies" in p && p.plies.length > 1) {
|
||||||
|
// self._targetUI.dispose();
|
||||||
|
self._link.property = {
|
||||||
|
id: p.plies[0],
|
||||||
|
name: p.name
|
||||||
|
};
|
||||||
|
self._link.target = {
|
||||||
|
nodeType: "anonymous",
|
||||||
|
links: [{
|
||||||
|
property: {
|
||||||
|
id: p.plies[1],
|
||||||
|
name: p.name2
|
||||||
|
},
|
||||||
|
target: self._link.target
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
self._renderDetails();
|
||||||
|
} else {
|
||||||
|
self._link.property = {
|
||||||
|
id: p.id,
|
||||||
|
name: p.name
|
||||||
|
};
|
||||||
|
}
|
||||||
|
self._configureTarget();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (suggestions.length > 0) {
|
||||||
|
var divSearch = $('<div>').addClass("schema-alignment-link-menu-type-search2").html('<div>Search for a property or pick one below</div>').appendTo(menu);
|
||||||
|
|
||||||
|
function createSuggestion(suggestion) {
|
||||||
|
var menuItem = MenuSystem.createMenuItem().appendTo(menu);
|
||||||
|
menuItem.html(suggestion.id).click(function() {
|
||||||
|
commitProperty(suggestion);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < suggestions.length; i++) {
|
||||||
|
createSuggestion(suggestions[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var divSearch = $('<div>').addClass("schema-alignment-link-menu-type-search").html('<div>Search for a property</div>').appendTo(menu);
|
||||||
|
}
|
||||||
|
var input = $('<input />').appendTo($('<div>').appendTo(divSearch));
|
||||||
|
|
||||||
|
MenuSystem.showMenu(menu, function(){});
|
||||||
|
MenuSystem.positionMenuAboveBelow(menu, $(elmt));
|
||||||
|
|
||||||
|
var suggestOptions = {
|
||||||
|
type : '/type/property'
|
||||||
|
};
|
||||||
|
if (this._link.target != null && "type" in this._link.target && this._link.target.type != null) {
|
||||||
|
suggestOptions.mql_filter = [{
|
||||||
|
"/type/property/expected_type" : {
|
||||||
|
id: this._link.target.type.id
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
} else {
|
||||||
|
var sourceTypeID = this._parentUINode.getExpectedType();
|
||||||
|
if (sourceTypeID != null) {
|
||||||
|
suggestOptions.mql_filter = [{
|
||||||
|
"/type/property/schema" : {
|
||||||
|
id: sourceTypeID
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
input.suggest(suggestOptions).bind("fb-select", function(e, data) { commitProperty(data); });
|
||||||
|
|
||||||
input[0].focus();
|
input[0].focus();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -140,6 +336,8 @@ SchemaAlignmentDialog.UILink.prototype.getJSON = function() {
|
|||||||
|
|
||||||
SchemaAlignmentDialog.UILink.prototype._configureTarget = function() {
|
SchemaAlignmentDialog.UILink.prototype._configureTarget = function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
var dismissBusy = DialogSystem.showBusy();
|
||||||
|
|
||||||
$.getJSON(
|
$.getJSON(
|
||||||
"http://api.freebase.com/api/service/mqlread?query=" + JSON.stringify({
|
"http://api.freebase.com/api/service/mqlread?query=" + JSON.stringify({
|
||||||
query: {
|
query: {
|
||||||
@ -154,6 +352,8 @@ SchemaAlignmentDialog.UILink.prototype._configureTarget = function() {
|
|||||||
}) + "&callback=?",
|
}) + "&callback=?",
|
||||||
null,
|
null,
|
||||||
function(o) {
|
function(o) {
|
||||||
|
dismissBusy();
|
||||||
|
|
||||||
if ("result" in o) {
|
if ("result" in o) {
|
||||||
var expected_type = o.result.expected_type;
|
var expected_type = o.result.expected_type;
|
||||||
self._link.target.type = {
|
self._link.target.type = {
|
||||||
@ -173,6 +373,9 @@ SchemaAlignmentDialog.UILink.prototype._configureTarget = function() {
|
|||||||
|
|
||||||
self._targetUI.render();
|
self._targetUI.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self._renderMain();
|
||||||
|
self._dialog.preview();
|
||||||
},
|
},
|
||||||
"jsonp"
|
"jsonp"
|
||||||
);
|
);
|
||||||
|
@ -23,6 +23,10 @@ SchemaAlignmentDialog.UINode = function(dialog, node, table, options) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SchemaAlignmentDialog.UINode.prototype.dispose = function() {
|
||||||
|
// nothing for now
|
||||||
|
};
|
||||||
|
|
||||||
SchemaAlignmentDialog.UINode.prototype.removeLink = function(linkUI) {
|
SchemaAlignmentDialog.UINode.prototype.removeLink = function(linkUI) {
|
||||||
for (var i = this._linkUIs.length - 1; i >= 0; i--) {
|
for (var i = this._linkUIs.length - 1; i >= 0; i--) {
|
||||||
if (this._linkUIs[i] === linkUI) {
|
if (this._linkUIs[i] === linkUI) {
|
||||||
@ -412,6 +416,7 @@ SchemaAlignmentDialog.UINode.prototype._showNodeConfigDialog = function() {
|
|||||||
elmts.cellAsTopicNodeTypeInput[0].value = typeName;
|
elmts.cellAsTopicNodeTypeInput[0].value = typeName;
|
||||||
elmts.cellAsTopicNodeTypeInput.data("data.suggest", { "id" : typeID, "name" : typeName });
|
elmts.cellAsTopicNodeTypeInput.data("data.suggest", { "id" : typeID, "name" : typeName });
|
||||||
elmts.radioNodeTypeCellAsTopicCreate[0].checked = true;
|
elmts.radioNodeTypeCellAsTopicCreate[0].checked = true;
|
||||||
|
elmts.radioNodeTypeCellAsTopic[0].checked = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -192,9 +192,9 @@ SchemaAlignmentDialog.prototype._constructFooter = function(footer) {
|
|||||||
|
|
||||||
SchemaAlignmentDialog.prototype._constructBody = function(body) {
|
SchemaAlignmentDialog.prototype._constructBody = function(body) {
|
||||||
$('<p>' +
|
$('<p>' +
|
||||||
'The protograph serves as a skeleton for the graph-shaped data that will get generated ' +
|
'The schema alignment skeleton below specifies how the graph-shaped data that will get generated ' +
|
||||||
'from your grid-shaped data and written into Freebase. The cells in each record of your data will ' +
|
'from your grid-shaped data and written into Freebase. The cells in each record of your data will ' +
|
||||||
'get placed into nodes within the protograph. Configure the protograph by specifying which ' +
|
'get placed into nodes within the skeleton. Configure the skeleton by specifying which ' +
|
||||||
'column to substitute into which node. A node can also be an automatically generated ' +
|
'column to substitute into which node. A node can also be an automatically generated ' +
|
||||||
'anonymous node, or it can be an explicit value or topic that is the same for all records.' +
|
'anonymous node, or it can be an explicit value or topic that is the same for all records.' +
|
||||||
'</p>').appendTo(body);
|
'</p>').appendTo(body);
|
||||||
@ -202,7 +202,7 @@ SchemaAlignmentDialog.prototype._constructBody = function(body) {
|
|||||||
$(
|
$(
|
||||||
'<div id="schema-alignment-tabs">' +
|
'<div id="schema-alignment-tabs">' +
|
||||||
'<ul>' +
|
'<ul>' +
|
||||||
'<li><a href="#schema-alignment-tabs-protograph">Protograph</a></li>' +
|
'<li><a href="#schema-alignment-tabs-protograph">Skeleton</a></li>' +
|
||||||
'<li><a href="#schema-alignment-tabs-preview-mqllike">MQL-like Preview</a></li>' +
|
'<li><a href="#schema-alignment-tabs-preview-mqllike">MQL-like Preview</a></li>' +
|
||||||
'<li><a href="#schema-alignment-tabs-preview-tripleloader">TripleLoader Preview</a></li>' +
|
'<li><a href="#schema-alignment-tabs-preview-tripleloader">TripleLoader Preview</a></li>' +
|
||||||
'</ul>' +
|
'</ul>' +
|
||||||
|
@ -125,3 +125,18 @@ table.schema-align-node-dialog-layout2 > tbody > tr:last-child > td {
|
|||||||
overflow: auto;
|
overflow: auto;
|
||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------
|
||||||
|
* Link dialog
|
||||||
|
*--------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
.schema-alignment-link-menu-type-search {
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.schema-alignment-link-menu-type-search2 {
|
||||||
|
padding: 8px;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
margin-bottom: 3px;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user