1
This commit is contained in:
Alex Yatskov 2015-06-29 19:09:34 +09:00
parent ae5dd26df3
commit 4fac0774cd
6 changed files with 91 additions and 91 deletions

View File

@ -59,8 +59,8 @@ func executeQuery(rw http.ResponseWriter, req *http.Request) {
sorter.sort()
response := jsonQueryResponse{
Count: len(foundEntries),
Columns: make(map[string]jsonColumn),
Count: len(foundEntries),
MinScore: request.MinScore,
Records: make([]jsonRecord, 0)}
@ -68,10 +68,10 @@ func executeQuery(rw http.ResponseWriter, req *http.Request) {
mode, _ := modes[name]
column := jsonColumn{
Bracket: jsonBracket{Max: -1, Min: 1},
Bracket: jsonBracket{Max: -1.0, Min: 1.0},
Mode: mode.String(),
Value: value,
Steps: request.Resolution}
Steps: request.Resolution,
Value: value}
hints := project(
entries,
@ -216,7 +216,6 @@ func removeCategory(rw http.ResponseWriter, req *http.Request) {
}
_, err := db.Exec("DELETE FROM categories WHERE id = (?)", request.Id)
js, err := json.Marshal(jsonRemoveCategoryResponse{err == nil})
if err != nil {
log.Fatal(err)
@ -295,8 +294,7 @@ func main() {
flag.Parse()
var err error
db, err = sql.Open("mysql", *dataSrc)
if err != nil {
if db, err = sql.Open("mysql", *dataSrc); err != nil {
log.Fatal(err)
}
defer db.Close()

View File

@ -11,7 +11,7 @@
</style>
</head>
<body>
<div class="container-fluid">
<div class="container">
<!-- busy spinner -->
<div class="page-header">
<img id="spinner" alt="loading" class="pull-right" src="images/spinner.gif" style="display: none;" width="32" height="32">
@ -80,14 +80,7 @@
<!-- visualizer -->
<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>
</div>
</div>
<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>

View File

@ -92,18 +92,18 @@
var _tickSize = 5;
var _width = 125;
var _indicatorAnim = null;
var _bracketAnim = null;
var _canvas = params.canvas;
var _data = params.data;
var _index = params.index;
var _name = params.name;
var _valueTrans = params.data.value;
var _bracketTrans = params.data.bracket;
var _onStateChanged = params.onStateChanged;
var _range = params.range;
var _scale = params.scale;
var _elements = {};
var _indicatorAnim = null;
var _bracketAnim = null;
var _canvas = params.canvas;
var _data = params.data;
var _index = params.index;
var _name = params.name;
var _valueTrans = params.data.value;
var _bracketTrans = params.data.bracket;
var _stateChanged = params.stateChanged;
var _range = params.range;
var _scale = params.scale;
var _elements = {};
function createShapes() {
// indicatorBg
@ -298,23 +298,25 @@
}
function updateMode() {
var modeText = '( ' + _data.mode + ' )';
var modes = {'product': 'importance', 'distance': 'similarity'};
var mode = modes[_data.mode];
if (_.has(_elements, 'mode')) {
_elements.mode.attr({
text: modeText
text: mode
});
}
else {
_elements.mode = _canvas.text(
(_width - _bracketSize) / 2,
_height - _panelSize / 4,
modeText
mode
).attr({
'dominant-baseline': 'middle',
'text-anchor': 'middle',
cursor: 'hand',
'fill': _modeColor
'text-decoration': 'underline',
'fill': _modeColor,
cursor: 'hand'
}).click(modeClick);
}
}
@ -354,8 +356,8 @@
_data.value = _range.clamp(value);
_data.mode = mode;
if (_onStateChanged) {
_onStateChanged(_name, _data.value, _data.mode);
if (_stateChanged) {
_stateChanged(_name, _data.value, _data.mode);
}
animateIndicator(_valueTrans, _data.value);
@ -493,13 +495,13 @@
//
grapher.Grapher = function(params) {
var _canvas = params.canvas;
var _columns = {};
var _data = {};
var _range = new Range(-1.0, 1.0);
var _useLocalScale = params.useLocalScale || false;
var _displayType = params.displayType || 'density';
var _onStateChanged = params.onStateChanged;
var _canvas = params.canvas;
var _columns = {};
var _data = {};
var _range = new Range(-1.0, 1.0);
var _useLocalScale = params.useLocalScale || false;
var _displayType = params.displayType || 'density';
var _stateChanged = params.stateChanged;
function processHintParameters(columns) {
var displayTypes = {compatibility: 'compatibility', density: 'count'};
@ -557,13 +559,13 @@
}
else {
_columns[name] = new Column({
onStateChanged: _onStateChanged,
range: _range,
canvas: _canvas,
data: columnData,
name: name,
scale: scale,
index: index++,
stateChanged: _stateChanged,
range: _range,
canvas: _canvas,
data: columnData,
name: name,
scale: scale,
index: index++,
});
}
}

View File

@ -25,7 +25,7 @@
var _ctx = {};
function onStateChanged(name, value, mode) {
function stateChanged(name, value, mode) {
_ctx.query.features[name] = value;
_ctx.query.modes[name] = mode;
@ -35,7 +35,7 @@
}, 'json');
}
function onReady(geo) {
function ready(geo) {
_ctx = {
sortKey: 'score',
sortAsc: false,
@ -98,10 +98,10 @@
$.post('/query', JSON.stringify(_ctx.query), function(results) {
if (!_.has(_ctx, 'grapher')) {
_ctx.grapher = new grapher.Grapher({
canvas: new Snap('#svg'),
onStateChanged: onStateChanged,
displayType: $('#displayType').val(),
useLocalScale: $('#useLocalScale').is(':checked')
canvas: new Snap('#svg'),
stateChanged: stateChanged,
displayType: $('#displayType').val(),
useLocalScale: $('#useLocalScale').is(':checked')
});
$('#useLocalScale').click(function() {
@ -200,13 +200,13 @@
ready: function() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
function(geo) { onReady(geo); },
function(err) { onReady(null); },
function(geo) { ready(geo); },
function(err) { ready(null); },
{ enableHighAccuracy: true }
);
}
else {
onReady(null);
ready(null);
}
}
});

View File

@ -22,18 +22,20 @@
package main
import "sort"
type modeType int
const (
ModeTypeNone modeType = iota
ModeTypeProduct
ModeTypeDistance
import (
"errors"
"sort"
)
type featureMap map[string]float64
type modeMap map[string]modeType
type records []record
type modeType int
const (
modeTypeProd = iota + 1
modeTypeDist
)
type jsonAccessRequest struct {
Id int `json:"id"`
@ -150,8 +152,6 @@ type record struct {
url string
}
type records []record
type recordSorter struct {
ascending bool
entries records
@ -198,22 +198,22 @@ func (s recordSorter) Swap(i, j int) {
func (m modeType) String() string {
switch m {
case ModeTypeProduct:
case modeTypeProd:
return "product"
case ModeTypeDistance:
case modeTypeDist:
return "distance"
default:
return "invalid"
return ""
}
}
func strToModeType(mode string) modeType {
func parseModeType(mode string) (modeType, error) {
switch mode {
case "product":
return ModeTypeProduct
return modeTypeProd, nil
case "distance":
return ModeTypeDistance
return modeTypeDist, nil
default:
return ModeTypeNone
return 0, errors.New("invalid mode type")
}
}

39
util.go
View File

@ -40,8 +40,9 @@ func fixFeatures(features featureMap) featureMap {
"atmospheric": 0.0}
for name := range fixedFeatures {
value, _ := features[name]
fixedFeatures[name] = value
if value, ok := features[name]; ok {
fixedFeatures[name] = value
}
}
return fixedFeatures
@ -49,42 +50,48 @@ func fixFeatures(features featureMap) featureMap {
func fixModes(modes map[string]string) modeMap {
fixedModes := modeMap{
"nearby": ModeTypeProduct,
"accessible": ModeTypeProduct,
"delicious": ModeTypeProduct,
"accommodating": ModeTypeProduct,
"affordable": ModeTypeProduct,
"atmospheric": ModeTypeProduct}
"nearby": modeTypeProd,
"accessible": modeTypeProd,
"delicious": modeTypeProd,
"accommodating": modeTypeProd,
"affordable": modeTypeProd,
"atmospheric": modeTypeProd}
for name := range fixedModes {
if value, ok := modes[name]; ok {
fixedModes[name] = strToModeType(value)
if mode, err := parseModeType(value); err == nil {
fixedModes[name] = mode
}
}
}
return fixedModes
}
func innerProduct(features1 featureMap, features2 featureMap) float64 {
var result float64
func distance(features1 featureMap, features2 featureMap) float64 {
var sum float64
for key, value1 := range features1 {
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 {
var result float64
for key, value1 := range features1 {
value2, _ := features2[key]
switch mode, _ := modes[key]; mode {
case ModeTypeDistance:
case modeTypeDist:
result += 1 - math.Abs(value1-value2)
default:
case modeTypeProd:
result += value1 * value2
default:
log.Fatal("unsupported compare mode")
}
}
@ -228,7 +235,7 @@ func computeRecordPopularity(entries records, context queryContext) {
log.Fatal(err)
}
groupSum += innerProduct(recordProfile, context.profile)
groupSum += distance(recordProfile, context.profile)
groupCount++
}
if err := historyRows.Err(); err != nil {