cleaned up and reduced scorer overhead

This commit is contained in:
Timo Volkmann 2020-06-25 15:01:21 +02:00
parent 2060eea09f
commit 6145c40654
8 changed files with 93 additions and 77 deletions

View File

@ -1,6 +0,0 @@
{
"temperature_mean_max": 5,
"precipitation": 3.5,
"raindays": 3,
"sunhours": 2.5
}

View File

@ -1,6 +0,0 @@
{
"id": 29837,
"parameter": "temperature",
"label": "warm",
"values": [22, 25]
}

View File

@ -9,8 +9,7 @@ const _ = require('lodash')
const base64 = require("../util/base64.js")
const scoreAndSearch = require("../util/scoreAndSearch.js");
const oldToNewQuerySyntax = require("../util/oldToNewQuerySyntax.js")
const { allTagsWithValues, getUniqueTags } = require("../models/getTags.js");
const { getClimateMinMax } = require("../util/getClimateMinMax.js");
const { getUniqueTags } = require("../models/getTags.js");
module.exports = dbConn => {
router.get("/api/v1/search", searchHandler(dbConn));
@ -61,10 +60,9 @@ function searchHandler(dbConn) {
// CHOOSE PARAMS WHICH SHALL BE PASSED TO SCORE AND SEARCH
let scoreQueryObj = prepareQueries(q)
let [regions, boundaryClimate] = await Promise.all([getRegions(dbConn), getClimateMinMax(dbConn)])
let [regions] = await Promise.all([getRegions(dbConn)])
let data = {
regions: regions,
boundaryClimate: boundaryClimate
}
// FILTER if query contains filterString
@ -82,28 +80,8 @@ function searchHandler(dbConn) {
console.log('without null scores');
searchResults.forEach(el => console.log('region:', el.name, 'score:', el.score))
searchResults = searchResults.filter(el => !_.some(el.scores, score => _.isNaN(score.score) || _.isNil(score.score) || score.score <= 0))
// searchResults = searchResults.filter(el => !(_.isNil(el.score) || _.isNaN(el.score)) )
// searchResults = searchResults.filter(el => {
// let nullcnt = 0
// el.scores.forEach(sc => {
// if (_.isNaN(sc.score) || sc.score <= 0 || _.isNil(el.score)) {
// nullcnt++
// }
// })
// console.log(el.name, nullcnt)
// return nullcnt >= 2 ? false : true
// })
/*searchResults = searchResults.filter(el => {
console.log('scorrrrrr', el.score);
let keepIt = true
//if (_.some(el.scores, score => score.score <= 0) && el.score < 1) keepIt = false
return cutScores ? keepIt : true
})//.filter(el => !_.isNaN(el.score))*/
}
// SEND RESPONSE
// response.data = searchResults
// res.json(response)
res.json(searchResults)
}).catch(e => {

62
backend/settings.js Normal file
View File

@ -0,0 +1,62 @@
module.exports = {
scoring: {
// parameter: [transition range, transition function, transistion slope exponent]
temperature_mean_max: [12, 'easeInOut', 2],
precipitation: [60, 'easeInOut', 2], // [170, 'easeInOut', 2],
rain_days: [5, 'easeInOut', 2],
sun_hours: [80, 'easeInOut', 2],
accommodation_costs: [30, 'linear', null],
food_costs: [25, 'linear', null],
alcohol_costs: [15, 'linear', null],
water_costs: [15, 'linear', null],
local_transportation_costs: [20, 'linear', null],
entertainment_costs: [20, 'easeInOut', 0.6],
average_per_day_costs: [100, 'linear', null],
avg_price_relative: [30, 'easeOut', 2],
},
boundaries: {
climate: {
min: {
temperature_mean: -9.6,
temperature_mean_min: -14.5,
temperature_mean_max: -4.7,
precipitation: 0,
rain_days: 0,
sun_hours: 3
},
max: {
temperature_mean: 38.3,
temperature_mean_min: 33.5,
temperature_mean_max: 43.7,
precipitation: 1145,
rain_days: 28,
sun_hours: 416
}
},
static: {
max: {
accommodation_costs: 500,
food_costs: 100,
alcohol_costs: 100,
water_costs: 100,
local_transportation_costs: 100,
entertainment_costs: 100,
average_per_day_costs: 1000,
avg_price_relative: 100
},
min: {
accommodation_costs: 0,
food_costs: 0,
alcohol_costs: 0,
water_costs: 0,
local_transportation_costs: 0,
entertainment_costs: 0,
average_per_day_costs: 0,
avg_price_relative: 0
}
}
}
}

View File

@ -1,9 +0,0 @@
const moment = require('moment')
let date = {
year: 2012,
month: 3,
day: 13
}
console.log(moment(date));

View File

View File

@ -4,17 +4,17 @@ exports.calculateAvgScore = (...scores) => {
return avgScore = scores.reduce((total, score) => total += score) / scores.length;
}
exports.calculateScoreRange = (min, max, multiplier, regionVal, sLowVal, sHighVal) => {
exports.calculateScoreRange = (transitionRange, regionVal, sLowVal, sHighVal) => {
//console.log('scores.calculateScoreRange:', min, max, multiplier, regionVal, sLowVal, sHighVal)
// return full score when in range
if (regionVal >= sLowVal && regionVal <= sHighVal) return 10;
// choose value with smallest distance
let sVal = Math.abs(regionVal - sLowVal) < Math.abs(regionVal - sHighVal) ? sLowVal : sHighVal;
return this.calculateScore(min, max, multiplier, regionVal, sVal);
return this.calculateScore(transitionRange, regionVal, sVal);
}
exports.calculateScore = (min, max, multiplier, regionVal, searchVal) => {
let score = 1 - (Math.abs(searchVal - regionVal) / (max - min) * multiplier);
exports.calculateScore = (transitionRange, regionVal, searchVal) => {
let score = 1 - (Math.abs(searchVal - regionVal) / transitionRange);
return (score) * 10;
//return score <= 0 ? 0 : score * 10;
}
@ -53,4 +53,14 @@ exports.sigmoid = function (x, exponent) {
const sigm = 10 / (1 + 8 * Math.pow(Math.E, 3/4 * -x))
console.log('sigmoid (IN/OUT):', _.round(x,3), _.round(sigm, 3))
return sigm
}
exports.increaseTransitionForHighValues = function (transitionRange, searchVal) {
//console.log(transitionRange);
// console.log(transitionRange);
// console.log(((Math.pow(searchVal / 20, 2) / 100) + 1));
// console.log(((Math.pow(searchVal / 20, 2) / 100) + 1) * transitionRange);
let transFactor = ((Math.pow(searchVal / 20, 2) / 100) + 1)
return transFactor >= 4 ? 4 * transitionRange : transFactor * transitionRange
}

View File

@ -1,26 +1,7 @@
const _ = require('lodash')
const moment = require("moment")
const getClimateMinMax = require("./getClimateMinMax.js")
const scorer = require('./score')
const getRegions = require('../models/getRegions.js')
const SHOW_ALL_SCOREOBJECTS = false
const SETTINGS = {
temperature_mean_max: [4.5, 'easeOut', 2],
precipitation: [4, 'easeInOut', 2],
rain_days: [2, 'easeInOut', 2],
sun_hours: [3.6, 'easeInOut', 2],
accommodation_costs: [17, 'linear', null],
food_costs: [4, 'linear', null],
alcohol_costs: [4, 'linear', null],
water_costs: [10, 'linear', null],
local_transportation_costs: [5, 'linear', null],
entertainment_costs: [5, 'easeInOut', 0.6],
average_per_day_costs: [5, 'linear', null],
avg_price_relative: [3, 'easeOut', 2],
}
const SETTINGS = require('../settings').scoring
module.exports = async function (data, from, to, q) {
console.log('search')
@ -28,7 +9,7 @@ module.exports = async function (data, from, to, q) {
if ((_.isNil(to) || _.isNil(from)) && !(_.isEmpty(q.climate) || _.isEmpty(q.costs) || _.isEmpty(q.others))) {
throw new Error('invalid query')
}
if (_.isNil(data) || _.isEmpty(data.regions) || _.isEmpty(data.boundaryClimate)) {
if (_.isNil(data) || _.isEmpty(data.regions)) {
throw new Error('database error')
}
let regionsArr = data.regions
@ -68,20 +49,20 @@ module.exports = async function (data, from, to, q) {
// CALCULATE SCORES FOR CLIMATE PROPS
reg.scores = []
Object.entries(q.climate).forEach(([key, value]) => {
let finalScoreObj = calculateScoreForPeriod(key, travelPeriods, reg, value[0], value[1], data.boundaryClimate)
let finalScoreObj = calculateScoreForPeriod(key, travelPeriods, reg, value[0], value[1])
reg.scores.push(finalScoreObj)
});
// CALCULATE SCORES FOR PRICE PROPS
Object.entries(q.costs).forEach(([key, value]) => {
let finalScoreObj = scoreFromSimpleRegionProperty(key, reg, value[0], value[1], boundaryStatic)
let finalScoreObj = scoreFromSimpleRegionProperty(key, reg, value[0], value[1])
reg.scores.push(finalScoreObj)
});
// CALCULATE SCORE FOR OFFSEASON
if (_.has(q, 'others.avg_price_relative')) {
let offSeasonScoreObj = calculateScoreForPeriod('avg_price_relative', travelPeriods, reg, q.others.avg_price_relative[0], q.others.avg_price_relative[1], boundaryStatic, 'easeOut', 2)
let offSeasonScoreObj = calculateScoreForPeriod('avg_price_relative', travelPeriods, reg, q.others.avg_price_relative[0], q.others.avg_price_relative[1], 'easeOut', 2)
reg.scores.push(offSeasonScoreObj)
}
@ -218,7 +199,7 @@ function createPeriod(from, to, currentMonth, currentYear) {
}
function calculateScoreForPeriod(type, travelPeriods, region, searchLowParam, searchMaxParam, minMax) {
function calculateScoreForPeriod(type, travelPeriods, region, searchLowParam, searchMaxParam) {
// console.log('getScoreAndAverageFromClimate for', region.name, type)
const singleScores = travelPeriods.map(period => {
@ -248,8 +229,14 @@ function calculateScoreForPeriod(type, travelPeriods, region, searchLowParam, se
})
averagedScore.value = _.round(averagedScore.value / averagedScore.days, 3)
delete averagedScore.days
let transitionRange = SETTINGS[type][0]
// special for precipitation
if (type === 'precipitation') {
transitionRange = scorer.increaseTransitionForHighValues(SETTINGS[type][0], searchLowParam)
}
let sc = scorer.calculateScoreRange(minMax.min[type], minMax.max[type], SETTINGS[type][0], averagedScore.value, searchLowParam, searchMaxParam)
let sc = scorer.calculateScoreRange(transitionRange, averagedScore.value, searchLowParam, searchMaxParam)
averagedScore.score = _.round(scorer[SETTINGS[type][1]](sc, SETTINGS[type][2]), 3)
// console.log('score', averagedScore.score)
if (searchLowParam === null) averagedScore.score = null
@ -267,7 +254,7 @@ function scoresFromTags(regionTags, tagStringsFromQueries) {
}
if (_.isNil(tag)) return retVal
retVal.value = tag.value
retVal.score = /* tag.value <= 0 ? 0 : */ _.round(scorer.calculateScoreRange(40, 100, 1, tag.value, 100, 100), 3)
retVal.score = /* tag.value <= 0 ? 0 : */ _.round(scorer.calculateScoreRange(60, tag.value, 100, 100), 3)
console.log(retVal);
return retVal
@ -276,7 +263,7 @@ function scoresFromTags(regionTags, tagStringsFromQueries) {
function scoreFromSimpleRegionProperty(type, region, searchLowParam, searchMaxParam, minMax) {
// console.log('getScoreFromCosts for', region.name, type)
const sc = _.round(scorer.calculateScoreRange(minMax.min[type], minMax.max[type], SETTINGS[type][0], region[type], searchLowParam, searchMaxParam), 3)
const sc = _.round(scorer.calculateScoreRange(SETTINGS[type][0], region[type], searchLowParam, searchMaxParam), 3)
let finScore = {
type: type,