Skip to content

Commit e79b9a4

Browse files
committed
Merge pull request #72 from MennaDarwish/elasticsearch/scoring
Elasticsearch/scoring
2 parents 6d61bdc + d245720 commit e79b9a4

File tree

5 files changed

+97
-87
lines changed

5 files changed

+97
-87
lines changed

db/seeds.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ sequelize.sync({ logging: console.log, force: true}).then(function() {
1919
domain: 'www.squib.co',
2020
password: 'password'
2121
}).then(function(advertiser) {
22-
var tags = ['finance', 'tennis', 'cars', 'basketball', 'sports', 'business', 'automotive']
22+
var tags = ['willThrow:) callback limbo','Finance', 'Tennis', 'Cars', 'Basketball', 'Sports', 'Business', 'Automotive']
2323
for(j = 0; j < 2000; j++) {
2424
var campaignTags = []
2525
tags.forEach(function(tag, index){
@@ -31,7 +31,7 @@ sequelize.sync({ logging: console.log, force: true}).then(function() {
3131
title: faker.lorem.sentence(),
3232
budget: faker.random.number(5000),
3333
advertiserId: 1,
34-
tags: campaignTags.join(', ')
34+
tags: campaignTags.join(' ')
3535
}).then(function(campaign) {
3636
var geoProperties = {}
3737
if(campaign.dataValues.id % 3 == 0) geoProperties = {city: faker.address.city(), country: faker.address.country()}

lib/bidder.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ return matcher(placement).then(function(response) {
2323
* So price = price + 0.01
2424
*
2525
*/
26-
winningAd._source['price'] = (runnerUp._score / winningAdQuality) + 0.01;
26+
winningAd._source['price'] = ((runnerUp._score / winningAdQuality) + 0.01)/1000;
2727
winningAd._source['creativeId'] = winningAd._id;
2828
return winningAd._source;
2929
});

lib/placement_matcher.js

Lines changed: 76 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,95 @@
11
var client = require('./elasticsearch/client');
22

33
module.exports = function(placement) {
4-
//construct should array
5-
6-
var interestsFiltersArray = [];
7-
var interests = placement.tags;
8-
interests.forEach(function(interest){
9-
var shouldObject = {
10-
term: { tags: interest}
11-
}
12-
interestsFiltersArray.push(shouldObject);
13-
});
4+
//construct should array
145
var placementCity = (placement.city || "").toLowerCase();
156
var placementCountry = (placement.country || "").toLowerCase();
16-
return client.search({
7+
var tags = placement.tags.join(" ");
8+
return client.search({
179
index: 'creatives',
1810
type: 'creative',
19-
//we only need the highest 2 creatives to calculate the price for the winning creative.
20-
body: {
21-
query: {
22-
function_score: {
23-
filter: {
24-
bool: {
25-
// each document should match ANY of the location condtions AND the ANY of the tags associated with the placement
26-
should: [
27-
{and:[
28-
{or:[
29-
{
30-
and: [
31-
{term: {targetCountry: placementCountry} },
32-
{script: {script: "doc['targetCity'].empty"}}
33-
]
34-
},
35-
{
36-
and: [
37-
{ term: {targetCountry: placementCountry} },
38-
{ term: { targetCity: placementCity} }
11+
body: {
12+
// we only need the highest 2 creatives.
13+
"size": 2,
14+
"query": {
15+
"function_score": {
16+
"field_value_factor": {
17+
"field": "cpm",
18+
"factor": 10
19+
},
20+
"query": {
21+
"bool": {
22+
"must": {
23+
"match": {
24+
// full-text search utilized to score relevance of tags.
25+
"tags": tags
26+
}
27+
},
28+
// a creative should match atleast one of the conditions in the should array
29+
"should": [
30+
{
31+
// match exact city and country in placement.
32+
"constant_score": {
33+
"filter": {
34+
"and": [
35+
{"term": {"targetCountry": placementCountry} },
36+
{"term": {"targetCity": placementCity} }
37+
]
38+
},
39+
"boost": 3
40+
}
41+
},
42+
{
43+
// match exact country and does not target a certain city.
44+
"constant_score": {
45+
"filter": {
46+
"and": [
47+
{"term": {"targetCountry": placementCountry}},
48+
{"missing":{"field": "targetCity" }}
3949
]
4050
},
41-
{
42-
script: {
43-
script: "doc['targetCountry'].empty && doc['targetOrigin'].empty"
44-
}
45-
},
46-
{
47-
and: [
48-
{
49-
script: {
50-
params: { "pLat": placement.latitude || 0.0, "pLon": placement.longitude || 0.0 },
51-
script: "!doc['targetOrigin'].empty && !doc['targetRadius'].empty && doc['targetOrigin'].distanceInKm(pLat, pLon) <= doc['targetRadius'].value"
52-
}
51+
"boost": 2
52+
}
53+
},
54+
{
55+
// match a certain area covered by a certain radius from a certian origin.
56+
"constant_score": {
57+
"filter": {
58+
"and": [
59+
{"missing": {"field": "targetCountry" }},
60+
{"missing": {"field": "targetCity" }},
61+
{
62+
"script": {
63+
"params": {
64+
"lat": placement.latitude || 0.0,
65+
"lon": placement.longitude || 0.0
66+
},
67+
"script": "!doc['targetOrigin'].empty && doc['targetOrigin'].distanceInKm(lat,lon) <= doc['targetRadius'].value"
5368
}
69+
}
5470
]
55-
}
56-
]
71+
},
72+
"boost": 4
73+
}
5774
},
5875
{
59-
or: interestsFiltersArray
76+
// no geolocation targeting at all
77+
"constant_score": {
78+
"filter": {
79+
"and":[
80+
{"missing" :{"field": "targetCountry"}},
81+
{"missing" : {"field": "targetCity"}},
82+
{"missing" : {"field": "targetOrigin"}}
83+
]
84+
},
85+
"boost": 1.2
86+
}
6087
}
61-
]
62-
}
63-
],
64-
must: [
65-
// each document mush match the exact width and height in the placement
66-
//TODO: created standard adTypes which will reduce this to one condition only.
67-
{term: {width: placement.width}},
68-
{term: {height: placement.height}}
69-
]
70-
}
71-
72-
},
73-
functions:[
74-
{
75-
script_score: {
76-
// the score depends on how matching is this creative with the placement, and how much does this creative cost.
77-
script: "_score*doc[\"cpm\"].value"
78-
}
88+
], "minimum_number_should_match": 1
7989
}
80-
]
90+
}
8191
}
8292
}
8393
}
84-
})
94+
});
8595
}

models/creative.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ var asIndexed = function() {
2020
.then(function(advertiser){
2121
var indexedHash = {
2222
id: _this.dataValues.id,
23-
tags: campaign.dataValues.tags.split(','),
23+
tags: campaign.dataValues.tags,
2424
advertiserId: advertiser.dataValues.id,
2525
campaignId: campaign.dataValues.id,
2626
remainingBudget: campaign.dataValues.budget,
@@ -73,14 +73,14 @@ module.exports = function(sequelize, DataTypes) {
7373
}, function(err) {
7474
callback(err);
7575
});
76-
},
77-
afterDestroy: function(record, options, callback) {
78-
esDocumentManager.deleteDocument(record.id, {index:'creatives', type:'creative'}).then(function(response) {
79-
callback(null, record);
80-
}, function(err){
81-
callback(err);
82-
});
8376
}
77+
//afterDestroy: function(record, options, callback) {
78+
//esDocumentManager.deleteDocument(record.id, {index:'creatives', type:'creative'}).then(function(response) {
79+
// callback(null, record);
80+
// }, function(err){
81+
// callback(err);
82+
// });
83+
// }
8484
}
8585
});
8686
return Creative;

test/routes/placements.js

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@ var db = require('../../models/index');
66

77
// Will create 10 campaigns creatives in test db which will be indexed in a testing elasticsearch index.
88
var campaignsData = [
9-
{budget: 3000, advertiserId: 1, tags: "finance,business,mba" },
10-
{budget: 2000, advertiserId: 1, tags: "sports,tennis" },
11-
{budget: 2500, advertiserId: 1, tags: "cars,automotive" },
12-
{budget: 5000, advertiserId: 1, tags: "motorcycles,automotive" },
13-
{budget: 3500, advertiserId: 1, tags: "football,basketball" },
14-
{budget: 5500, advertiserId: 1, tags: "business,stockmarket" },
15-
{budget: 5500, advertiserId: 1, tags: "suits,clothe,business" },
16-
{budget: 1000, advertiserId: 1, tags: "finance,stockmarket" },
17-
{budget: 1000, advertiserId: 1, tags: "football,sports,tennis" },
18-
{budget: 3000, advertiserId: 1, tags: "automotive,motorcycles,cars"}
9+
{budget: 3000, advertiserId: 1, tags: "Finance Business Mba" },
10+
{budget: 2000, advertiserId: 1, tags: "Sports Tennis" },
11+
{budget: 2500, advertiserId: 1, tags: "Cars Automotive" },
12+
{budget: 5000, advertiserId: 1, tags: "Motorcycles Automotive" },
13+
{budget: 3500, advertiserId: 1, tags: "Football Basketball" },
14+
{budget: 5500, advertiserId: 1, tags: "Business Stockmarket" },
15+
{budget: 5500, advertiserId: 1, tags: "Suits Clothes Business" },
16+
{budget: 1000, advertiserId: 1, tags: "Finance Stockmarket" },
17+
{budget: 1000, advertiserId: 1, tags: "Football Sports Tennis" },
18+
{budget: 3000, advertiserId: 1, tags: "Automotive Motorcycles Cars"}
1919
]
2020
var geoTargetData = [
2121
{city: 'Cairo', country: 'Egypt', campaignId:1}, // city targeting

0 commit comments

Comments
 (0)