Cleanup
This commit is contained in:
parent
ae5dd26df3
commit
4fac0774cd
12
server.go
12
server.go
@ -59,8 +59,8 @@ func executeQuery(rw http.ResponseWriter, req *http.Request) {
|
|||||||
sorter.sort()
|
sorter.sort()
|
||||||
|
|
||||||
response := jsonQueryResponse{
|
response := jsonQueryResponse{
|
||||||
Count: len(foundEntries),
|
|
||||||
Columns: make(map[string]jsonColumn),
|
Columns: make(map[string]jsonColumn),
|
||||||
|
Count: len(foundEntries),
|
||||||
MinScore: request.MinScore,
|
MinScore: request.MinScore,
|
||||||
Records: make([]jsonRecord, 0)}
|
Records: make([]jsonRecord, 0)}
|
||||||
|
|
||||||
@ -68,10 +68,10 @@ func executeQuery(rw http.ResponseWriter, req *http.Request) {
|
|||||||
mode, _ := modes[name]
|
mode, _ := modes[name]
|
||||||
|
|
||||||
column := jsonColumn{
|
column := jsonColumn{
|
||||||
Bracket: jsonBracket{Max: -1, Min: 1},
|
Bracket: jsonBracket{Max: -1.0, Min: 1.0},
|
||||||
Mode: mode.String(),
|
Mode: mode.String(),
|
||||||
Value: value,
|
Steps: request.Resolution,
|
||||||
Steps: request.Resolution}
|
Value: value}
|
||||||
|
|
||||||
hints := project(
|
hints := project(
|
||||||
entries,
|
entries,
|
||||||
@ -216,7 +216,6 @@ func removeCategory(rw http.ResponseWriter, req *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, err := db.Exec("DELETE FROM categories WHERE id = (?)", request.Id)
|
_, err := db.Exec("DELETE FROM categories WHERE id = (?)", request.Id)
|
||||||
|
|
||||||
js, err := json.Marshal(jsonRemoveCategoryResponse{err == nil})
|
js, err := json.Marshal(jsonRemoveCategoryResponse{err == nil})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
@ -295,8 +294,7 @@ func main() {
|
|||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
db, err = sql.Open("mysql", *dataSrc)
|
if db, err = sql.Open("mysql", *dataSrc); err != nil {
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container-fluid">
|
<div class="container">
|
||||||
<!-- busy spinner -->
|
<!-- busy spinner -->
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<img id="spinner" alt="loading" class="pull-right" src="images/spinner.gif" style="display: none;" width="32" height="32">
|
<img id="spinner" alt="loading" class="pull-right" src="images/spinner.gif" style="display: none;" width="32" height="32">
|
||||||
@ -80,16 +80,9 @@
|
|||||||
|
|
||||||
<!-- visualizer -->
|
<!-- visualizer -->
|
||||||
<div class="col-md-9">
|
<div class="col-md-9">
|
||||||
<div class="panel panel-default">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<big>Visualizer</big>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body text-center">
|
|
||||||
<svg id="svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="800" height="500"></svg>
|
<svg id="svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="800" height="500"></svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- result listing -->
|
<!-- result listing -->
|
||||||
<div class="panel panel-default" style="display: none;" id="resultPanel">
|
<div class="panel panel-default" style="display: none;" id="resultPanel">
|
||||||
|
@ -100,7 +100,7 @@
|
|||||||
var _name = params.name;
|
var _name = params.name;
|
||||||
var _valueTrans = params.data.value;
|
var _valueTrans = params.data.value;
|
||||||
var _bracketTrans = params.data.bracket;
|
var _bracketTrans = params.data.bracket;
|
||||||
var _onStateChanged = params.onStateChanged;
|
var _stateChanged = params.stateChanged;
|
||||||
var _range = params.range;
|
var _range = params.range;
|
||||||
var _scale = params.scale;
|
var _scale = params.scale;
|
||||||
var _elements = {};
|
var _elements = {};
|
||||||
@ -298,23 +298,25 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateMode() {
|
function updateMode() {
|
||||||
var modeText = '( ' + _data.mode + ' )';
|
var modes = {'product': 'importance', 'distance': 'similarity'};
|
||||||
|
var mode = modes[_data.mode];
|
||||||
|
|
||||||
if (_.has(_elements, 'mode')) {
|
if (_.has(_elements, 'mode')) {
|
||||||
_elements.mode.attr({
|
_elements.mode.attr({
|
||||||
text: modeText
|
text: mode
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
_elements.mode = _canvas.text(
|
_elements.mode = _canvas.text(
|
||||||
(_width - _bracketSize) / 2,
|
(_width - _bracketSize) / 2,
|
||||||
_height - _panelSize / 4,
|
_height - _panelSize / 4,
|
||||||
modeText
|
mode
|
||||||
).attr({
|
).attr({
|
||||||
'dominant-baseline': 'middle',
|
'dominant-baseline': 'middle',
|
||||||
'text-anchor': 'middle',
|
'text-anchor': 'middle',
|
||||||
cursor: 'hand',
|
'text-decoration': 'underline',
|
||||||
'fill': _modeColor
|
'fill': _modeColor,
|
||||||
|
cursor: 'hand'
|
||||||
}).click(modeClick);
|
}).click(modeClick);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -354,8 +356,8 @@
|
|||||||
_data.value = _range.clamp(value);
|
_data.value = _range.clamp(value);
|
||||||
_data.mode = mode;
|
_data.mode = mode;
|
||||||
|
|
||||||
if (_onStateChanged) {
|
if (_stateChanged) {
|
||||||
_onStateChanged(_name, _data.value, _data.mode);
|
_stateChanged(_name, _data.value, _data.mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
animateIndicator(_valueTrans, _data.value);
|
animateIndicator(_valueTrans, _data.value);
|
||||||
@ -499,7 +501,7 @@
|
|||||||
var _range = new Range(-1.0, 1.0);
|
var _range = new Range(-1.0, 1.0);
|
||||||
var _useLocalScale = params.useLocalScale || false;
|
var _useLocalScale = params.useLocalScale || false;
|
||||||
var _displayType = params.displayType || 'density';
|
var _displayType = params.displayType || 'density';
|
||||||
var _onStateChanged = params.onStateChanged;
|
var _stateChanged = params.stateChanged;
|
||||||
|
|
||||||
function processHintParameters(columns) {
|
function processHintParameters(columns) {
|
||||||
var displayTypes = {compatibility: 'compatibility', density: 'count'};
|
var displayTypes = {compatibility: 'compatibility', density: 'count'};
|
||||||
@ -557,7 +559,7 @@
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
_columns[name] = new Column({
|
_columns[name] = new Column({
|
||||||
onStateChanged: _onStateChanged,
|
stateChanged: _stateChanged,
|
||||||
range: _range,
|
range: _range,
|
||||||
canvas: _canvas,
|
canvas: _canvas,
|
||||||
data: columnData,
|
data: columnData,
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
var _ctx = {};
|
var _ctx = {};
|
||||||
|
|
||||||
function onStateChanged(name, value, mode) {
|
function stateChanged(name, value, mode) {
|
||||||
_ctx.query.features[name] = value;
|
_ctx.query.features[name] = value;
|
||||||
_ctx.query.modes[name] = mode;
|
_ctx.query.modes[name] = mode;
|
||||||
|
|
||||||
@ -35,7 +35,7 @@
|
|||||||
}, 'json');
|
}, 'json');
|
||||||
}
|
}
|
||||||
|
|
||||||
function onReady(geo) {
|
function ready(geo) {
|
||||||
_ctx = {
|
_ctx = {
|
||||||
sortKey: 'score',
|
sortKey: 'score',
|
||||||
sortAsc: false,
|
sortAsc: false,
|
||||||
@ -99,7 +99,7 @@
|
|||||||
if (!_.has(_ctx, 'grapher')) {
|
if (!_.has(_ctx, 'grapher')) {
|
||||||
_ctx.grapher = new grapher.Grapher({
|
_ctx.grapher = new grapher.Grapher({
|
||||||
canvas: new Snap('#svg'),
|
canvas: new Snap('#svg'),
|
||||||
onStateChanged: onStateChanged,
|
stateChanged: stateChanged,
|
||||||
displayType: $('#displayType').val(),
|
displayType: $('#displayType').val(),
|
||||||
useLocalScale: $('#useLocalScale').is(':checked')
|
useLocalScale: $('#useLocalScale').is(':checked')
|
||||||
});
|
});
|
||||||
@ -200,13 +200,13 @@
|
|||||||
ready: function() {
|
ready: function() {
|
||||||
if (navigator.geolocation) {
|
if (navigator.geolocation) {
|
||||||
navigator.geolocation.getCurrentPosition(
|
navigator.geolocation.getCurrentPosition(
|
||||||
function(geo) { onReady(geo); },
|
function(geo) { ready(geo); },
|
||||||
function(err) { onReady(null); },
|
function(err) { ready(null); },
|
||||||
{ enableHighAccuracy: true }
|
{ enableHighAccuracy: true }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
onReady(null);
|
ready(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
34
types.go
34
types.go
@ -22,18 +22,20 @@
|
|||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import "sort"
|
import (
|
||||||
|
"errors"
|
||||||
type modeType int
|
"sort"
|
||||||
|
|
||||||
const (
|
|
||||||
ModeTypeNone modeType = iota
|
|
||||||
ModeTypeProduct
|
|
||||||
ModeTypeDistance
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type featureMap map[string]float64
|
type featureMap map[string]float64
|
||||||
type modeMap map[string]modeType
|
type modeMap map[string]modeType
|
||||||
|
type records []record
|
||||||
|
type modeType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
modeTypeProd = iota + 1
|
||||||
|
modeTypeDist
|
||||||
|
)
|
||||||
|
|
||||||
type jsonAccessRequest struct {
|
type jsonAccessRequest struct {
|
||||||
Id int `json:"id"`
|
Id int `json:"id"`
|
||||||
@ -150,8 +152,6 @@ type record struct {
|
|||||||
url string
|
url string
|
||||||
}
|
}
|
||||||
|
|
||||||
type records []record
|
|
||||||
|
|
||||||
type recordSorter struct {
|
type recordSorter struct {
|
||||||
ascending bool
|
ascending bool
|
||||||
entries records
|
entries records
|
||||||
@ -198,22 +198,22 @@ func (s recordSorter) Swap(i, j int) {
|
|||||||
|
|
||||||
func (m modeType) String() string {
|
func (m modeType) String() string {
|
||||||
switch m {
|
switch m {
|
||||||
case ModeTypeProduct:
|
case modeTypeProd:
|
||||||
return "product"
|
return "product"
|
||||||
case ModeTypeDistance:
|
case modeTypeDist:
|
||||||
return "distance"
|
return "distance"
|
||||||
default:
|
default:
|
||||||
return "invalid"
|
return ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func strToModeType(mode string) modeType {
|
func parseModeType(mode string) (modeType, error) {
|
||||||
switch mode {
|
switch mode {
|
||||||
case "product":
|
case "product":
|
||||||
return ModeTypeProduct
|
return modeTypeProd, nil
|
||||||
case "distance":
|
case "distance":
|
||||||
return ModeTypeDistance
|
return modeTypeDist, nil
|
||||||
default:
|
default:
|
||||||
return ModeTypeNone
|
return 0, errors.New("invalid mode type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
37
util.go
37
util.go
@ -40,51 +40,58 @@ func fixFeatures(features featureMap) featureMap {
|
|||||||
"atmospheric": 0.0}
|
"atmospheric": 0.0}
|
||||||
|
|
||||||
for name := range fixedFeatures {
|
for name := range fixedFeatures {
|
||||||
value, _ := features[name]
|
if value, ok := features[name]; ok {
|
||||||
fixedFeatures[name] = value
|
fixedFeatures[name] = value
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return fixedFeatures
|
return fixedFeatures
|
||||||
}
|
}
|
||||||
|
|
||||||
func fixModes(modes map[string]string) modeMap {
|
func fixModes(modes map[string]string) modeMap {
|
||||||
fixedModes := modeMap{
|
fixedModes := modeMap{
|
||||||
"nearby": ModeTypeProduct,
|
"nearby": modeTypeProd,
|
||||||
"accessible": ModeTypeProduct,
|
"accessible": modeTypeProd,
|
||||||
"delicious": ModeTypeProduct,
|
"delicious": modeTypeProd,
|
||||||
"accommodating": ModeTypeProduct,
|
"accommodating": modeTypeProd,
|
||||||
"affordable": ModeTypeProduct,
|
"affordable": modeTypeProd,
|
||||||
"atmospheric": ModeTypeProduct}
|
"atmospheric": modeTypeProd}
|
||||||
|
|
||||||
for name := range fixedModes {
|
for name := range fixedModes {
|
||||||
if value, ok := modes[name]; ok {
|
if value, ok := modes[name]; ok {
|
||||||
fixedModes[name] = strToModeType(value)
|
if mode, err := parseModeType(value); err == nil {
|
||||||
|
fixedModes[name] = mode
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fixedModes
|
return fixedModes
|
||||||
}
|
}
|
||||||
|
|
||||||
func innerProduct(features1 featureMap, features2 featureMap) float64 {
|
func distance(features1 featureMap, features2 featureMap) float64 {
|
||||||
var result float64
|
var sum float64
|
||||||
|
|
||||||
for key, value1 := range features1 {
|
for key, value1 := range features1 {
|
||||||
value2, _ := features2[key]
|
value2, _ := features2[key]
|
||||||
result += value1 * value2
|
sum += math.Pow(value1-value2, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return math.Sqrt(sum)
|
||||||
}
|
}
|
||||||
|
|
||||||
func compare(features1 featureMap, features2 featureMap, modes modeMap) float64 {
|
func compare(features1 featureMap, features2 featureMap, modes modeMap) float64 {
|
||||||
var result float64
|
var result float64
|
||||||
|
|
||||||
for key, value1 := range features1 {
|
for key, value1 := range features1 {
|
||||||
value2, _ := features2[key]
|
value2, _ := features2[key]
|
||||||
|
|
||||||
switch mode, _ := modes[key]; mode {
|
switch mode, _ := modes[key]; mode {
|
||||||
case ModeTypeDistance:
|
case modeTypeDist:
|
||||||
result += 1 - math.Abs(value1-value2)
|
result += 1 - math.Abs(value1-value2)
|
||||||
default:
|
case modeTypeProd:
|
||||||
result += value1 * value2
|
result += value1 * value2
|
||||||
|
default:
|
||||||
|
log.Fatal("unsupported compare mode")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,7 +235,7 @@ func computeRecordPopularity(entries records, context queryContext) {
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
groupSum += innerProduct(recordProfile, context.profile)
|
groupSum += distance(recordProfile, context.profile)
|
||||||
groupCount++
|
groupCount++
|
||||||
}
|
}
|
||||||
if err := historyRows.Err(); err != nil {
|
if err := historyRows.Err(); err != nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user