diff --git a/backend/mockdata/multiplier.json b/backend/mockdata/multiplier.json deleted file mode 100644 index 50f0faf..0000000 --- a/backend/mockdata/multiplier.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "temperature_mean_max": 5, - "precipitation": 3.5, - "raindays": 3, - "sunhours": 2.5 -} \ No newline at end of file diff --git a/backend/mockdata/sample-presets.json b/backend/mockdata/sample-presets.json deleted file mode 100644 index 5293a34..0000000 --- a/backend/mockdata/sample-presets.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "id": 29837, - "parameter": "temperature", - "label": "warm", - "values": [22, 25] -} \ No newline at end of file diff --git a/backend/routes/search.js b/backend/routes/search.js index 1fa7bc6..43c390e 100644 --- a/backend/routes/search.js +++ b/backend/routes/search.js @@ -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 => { diff --git a/backend/settings.js b/backend/settings.js new file mode 100644 index 0000000..a3318e4 --- /dev/null +++ b/backend/settings.js @@ -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 + } + } + } +} \ No newline at end of file diff --git a/backend/test.js b/backend/test.js deleted file mode 100644 index e358986..0000000 --- a/backend/test.js +++ /dev/null @@ -1,9 +0,0 @@ -const moment = require('moment') - -let date = { - year: 2012, - month: 3, - day: 13 -} - -console.log(moment(date)); diff --git a/backend/util/prices.js b/backend/util/prices.js deleted file mode 100644 index e69de29..0000000 diff --git a/backend/util/score.js b/backend/util/score.js index 298f313..334897a 100644 --- a/backend/util/score.js +++ b/backend/util/score.js @@ -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 } \ No newline at end of file diff --git a/backend/util/scoreAndSearch.js b/backend/util/scoreAndSearch.js index 4b6aba8..14ba8c2 100644 --- a/backend/util/scoreAndSearch.js +++ b/backend/util/scoreAndSearch.js @@ -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,