1

Removing keywords from server and client

This commit is contained in:
Alex Yatskov 2015-01-13 16:36:22 +09:00
parent eece4dd876
commit 4f4713ec46
5 changed files with 40 additions and 238 deletions

View File

@ -18,10 +18,6 @@
<div class="col-md-7"> <div class="col-md-7">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<div class="pull-right">
<button class="btn btn-xs btn-danger" id="forget">Forget</button>
<button class="btn btn-xs btn-default" id="learn">Learn</button>
</div>
<big>Visualizer</big> <big>Visualizer</big>
</div> </div>
<div class="panel-body"> <div class="panel-body">
@ -37,10 +33,6 @@
<big>Query</big> <big>Query</big>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<div class="form-group">
<label for="searchKeyword">Keyword <span class="label label-warning" id="customized" style="display: none;">Cutomized</span></label>
<select id="searchKeyword" class="form-control"></select>
</div>
<div class="form-group"> <div class="form-group">
<label for="walkingDist">Walking distance (km)</label> <label for="walkingDist">Walking distance (km)</label>
<input class="form-control" type="number" step="0.1" min="0.1" value="1.0" id="walkingDist"> <input class="form-control" type="number" step="0.1" min="0.1" value="1.0" id="walkingDist">

View File

@ -1,28 +1,23 @@
/* /*
* Copyright (c) 2015 Alex Yatskov <alex@foosoft.net>
The MIT License (MIT) *
* Permission is hereby granted, free of charge, to any person obtaining a copy of
Copyright (c) 2014 Alex Yatskov * this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
Permission is hereby granted, free of charge, to any person obtaining a copy * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
of this software and associated documentation files (the "Software"), to deal * the Software, and to permit persons to whom the Software is furnished to do so,
in the Software without restriction, including without limitation the rights * subject to the following conditions:
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell *
copies of the Software, and to permit persons to whom the Software is * The above copyright notice and this permission notice shall be included in all
furnished to do so, subject to the following conditions: * copies or substantial portions of the Software.
*
The above copyright notice and this permission notice shall be included in * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
all copies or substantial portions of the Software. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
(function(hscd) { (function(hscd) {
'use strict'; 'use strict';
@ -34,7 +29,6 @@
$.getJSON('/search', _ctx.query, function(results) { $.getJSON('/search', _ctx.query, function(results) {
saveSnapshot(results); saveSnapshot(results);
outputSnapshot(results, true); outputSnapshot(results, true);
setCustomized(true);
}); });
} }
@ -60,84 +54,17 @@
$.getJSON('/get_parameters', function(parameters) { $.getJSON('/get_parameters', function(parameters) {
_ctx.parameters = parameters; _ctx.parameters = parameters;
for (var keyword in parameters.keywords) {
$('#searchKeyword').append($('<option></option>', { value: keyword, text: keyword }));
}
onSearch(); onSearch();
$('#searchKeyword').change(function() { onSearch(); });
$('#minScore,#hintSteps,#walkingDist,#maxResults').change(function() { onSearch(getFeaturesGrapher); }); $('#minScore,#hintSteps,#walkingDist,#maxResults').change(function() { onSearch(getFeaturesGrapher); });
$('#historyIndex').on('slideStop', onSelectSnapshot); $('#historyIndex').on('slideStop', onSelectSnapshot);
$('#learn').click(onLearn);
$('#forget').click(onForget);
$('#customized').click(onReset);
}); });
} }
function onReset() {
if (confirm('Reset customizations?')) {
onSearch();
}
}
function onLearn() {
var keyword = prompt('Learn keyword as');
if (keyword === null) {
return;
}
var query = {
keyword: keyword,
features: _ctx.query.features
};
$.getJSON('/add_keyword', query, function(results) {
if (results.success) {
_ctx.parameters.keywords[keyword] = _.clone(query.features);
$('#searchKeyword').append($('<option></option>', { value: keyword, text: keyword }));
$('#searchKeyword').val(keyword);
setCustomized(false);
}
else {
alert('Failed to learn keyword');
}
});
}
function onForget() {
var keyword = $('#searchKeyword').val();
if (!confirm('Are you sure you want to delete keyword "' + keyword + '"?')) {
return;
}
var query = {
keyword: keyword
};
$.getJSON('/remove_keyword', query, function(results) {
if (results.success) {
$('#searchKeyword option:selected').remove();
onSearch();
}
else {
alert('Failed to forget keyword');
}
});
}
function getFeaturesKeyword() {
var keyword = $('#searchKeyword').val();
return _.clone(_ctx.parameters.keywords[keyword]);
}
function getFeaturesGrapher() {
return _.clone(_ctx.query.features);
}
function onSearch(provider) { function onSearch(provider) {
_ctx.query = { _ctx.query = {
features: (provider || getFeaturesKeyword)(), features: _clone(_ctx.query.features),
range: { min: -1.0, max: 1.0 }, range: { min: -1.0, max: 1.0 },
walkingDist: parseFloat($('#walkingDist').val()), walkingDist: parseFloat($('#walkingDist').val()),
minScore: parseFloat($('#minScore').val()), minScore: parseFloat($('#minScore').val()),
@ -185,14 +112,12 @@
$.getJSON('/search', _ctx.query, function(results) { $.getJSON('/search', _ctx.query, function(results) {
saveSnapshot(results); saveSnapshot(results);
outputSnapshot(results, false); outputSnapshot(results, false);
setCustomized(false);
}); });
} }
function onSelectSnapshot() { function onSelectSnapshot() {
var index = $('#historyIndex').slider('getValue'); var index = $('#historyIndex').slider('getValue');
outputSnapshot(_ctx.log[index], false); outputSnapshot(_ctx.log[index], false);
setCustomized(true);
} }
function saveSnapshot(results) { function saveSnapshot(results) {
@ -208,17 +133,6 @@
} }
} }
function setCustomized(customized) {
if (customized) {
$('#customized').show();
$('#forget').hide();
}
else {
$('#customized').hide();
$('#forget').show();
}
}
function outputSnapshot(results, omitValues) { function outputSnapshot(results, omitValues) {
var columns = {}; var columns = {};
for (var name in results.columns) { for (var name in results.columns) {

View File

@ -1,28 +1,23 @@
/* /*
* Copyright (c) 2015 Alex Yatskov <alex@foosoft.net>
The MIT License (MIT) *
* Permission is hereby granted, free of charge, to any person obtaining a copy of
Copyright (c) 2014 Alex Yatskov * this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
Permission is hereby granted, free of charge, to any person obtaining a copy * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
of this software and associated documentation files (the "Software"), to deal * the Software, and to permit persons to whom the Software is furnished to do so,
in the Software without restriction, including without limitation the rights * subject to the following conditions:
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell *
copies of the Software, and to permit persons to whom the Software is * The above copyright notice and this permission notice shall be included in all
furnished to do so, subject to the following conditions: * copies or substantial portions of the Software.
*
The above copyright notice and this permission notice shall be included in * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
all copies or substantial portions of the Software. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
(function(grapher) { (function(grapher) {
'use strict'; 'use strict';

View File

@ -133,67 +133,6 @@ function loadDb(params) {
pool = mysql.createPool(params); pool = mysql.createPool(params);
} }
function addKeyword(query, callback) {
if (!/^[a-zA-Z0-9\s\-]+$/.test(query.keyword)) {
callback({
keyword: query.keyword,
success: false
});
return;
}
getKeywords(function(keywords) {
var values = [
query.keyword,
query.features.delicious,
query.features.accomodating,
query.features.affordable,
query.features.atmospheric,
query.features.nearby,
query.features.accessible
];
pool.query('INSERT INTO keywords VALUES(?, ?, ?, ?, ?, ?, ?)', values, function(err) {
callback({
keyword: query.keyword,
success: err === null
});
});
});
}
function removeKeyword(query, callback) {
pool.query('DELETE FROM keywords WHERE name=? AND name NOT IN (SELECT name FROM presets)', [query.keyword], function(err, fields) {
callback({
keyword: query.keyword,
success: err === null && fields.affectedRows > 0
});
});
}
function getKeywords(callback) {
pool.query('SELECT * FROM keywords', function(err, rows) {
if (err) {
throw err;
}
var keywords = {};
for (var i = 0, count = rows.length; i < count; ++i) {
var row = rows[i];
keywords[row.name] = {
delicious: row.delicious,
accomodating: row.accomodating,
affordable: row.affordable,
atmospheric: row.atmospheric,
nearby: row.nearby,
accessible: row.access
};
}
callback(keywords);
});
}
function getRecords(context, callback) { function getRecords(context, callback) {
pool.query('SELECT * FROM reviews', function(err, rows) { pool.query('SELECT * FROM reviews', function(err, rows) {
if (err) { if (err) {
@ -250,30 +189,13 @@ function computeRecordGeo(records, context) {
}); });
} }
function getData(context, callback) {
getKeywords(function(keywords) {
getRecords(context, function(records) {
callback({
keywords: keywords,
records: records
});
});
});
}
function getParameters(callback) {
getKeywords(function(keywords) {
callback({keywords: keywords});
});
}
function execQuery(query, callback) { function execQuery(query, callback) {
var context = { var context = {
geo: query.geo, geo: query.geo,
walkingDist: query.walkingDist * 1000.0 walkingDist: query.walkingDist * 1000.0
}; };
getData(context, function(data) { getRecords(context, function(data) {
var searchResults = findRecords( var searchResults = findRecords(
data, data,
query.features, query.features,
@ -308,8 +230,5 @@ function execQuery(query, callback) {
module.exports = { module.exports = {
loadDb: loadDb, loadDb: loadDb,
addKeyword: addKeyword,
removeKeyword: removeKeyword,
getParameters: getParameters,
execQuery: execQuery execQuery: execQuery
}; };

View File

@ -39,24 +39,6 @@ function main(staticFiles, port) {
user: 'hscd' user: 'hscd'
}); });
app.use('/get_parameters', function(req, res) {
search.getParameters(function(parameters) {
res.json(parameters);
});
});
app.use('/add_keyword', function(req, res) {
search.addKeyword(req.query, function(results) {
res.json(results);
});
});
app.use('/remove_keyword', function(req, res) {
search.removeKeyword(req.query, function(results) {
res.json(results);
});
});
app.use('/search', function(req, res) { app.use('/search', function(req, res) {
search.execQuery(req.query, function(results) { search.execQuery(req.query, function(results) {
res.json(results); res.json(results);