Sfoglia il codice sorgente

:sparkles: using cos similarity for quick scoring

tags/0.0.1
j 4 anni fa
parent
commit
e02a9fde1e
3 ha cambiato i file con 120 aggiunte e 17 eliminazioni
  1. 40
    17
      backend/db/survey-generator.js
  2. 79
    0
      backend/package-lock.json
  3. 1
    0
      backend/package.json

+ 40
- 17
backend/db/survey-generator.js Vedi File

@@ -1,9 +1,13 @@
1
+const similarity = require('compute-cosine-similarity')
2
+const magic = 1000 // Multiply cosine similary by this
3
+
1 4
 const not_important = '120'
2 5
 const somewhat_important = '140'
3 6
 const important = '160'
4 7
 const very_important = '180'
5 8
 const extremely_important = '200'
6 9
 const mandatory = '400'
10
+
7 11
 // -
8 12
 // 1440 - 2400 total range
9 13
 // 1440 - 1900 limited range
@@ -59,6 +63,7 @@ const rand = max => {
59 63
 
60 64
 class DummyProfile {
61 65
     constructor() {
66
+        this.id = null
62 67
         this.profileResponses = null
63 68
         this.langPref = null
64 69
         this.durationPref = null
@@ -84,15 +89,18 @@ const generateDummyProfiles = count => {
84 89
     const profiles = []
85 90
     for (let i = 0; i < count; i++) {
86 91
         const dummyProfile = new DummyProfile()
92
+        dummyProfile.id = i + 1
87 93
         profiles.push(dummyProfile)
88 94
     }
89 95
     profiles.forEach(dummy => {
90
-        dummy.profileResponses = dummy.profileResponses.map(answer => {
91
-            const answerObj = {}
92
-            const random = rand(12)
93
-            answerObj[random] = answer
94
-            return answerObj
95
-        })
96
+        dummy.profileResponses = dummy.profileResponses.map(
97
+            (answer, response_key_id) => {
98
+                const answerObj = {}
99
+                // aka: id for the question we asked
100
+                answerObj[response_key_id] = answer
101
+                return answerObj
102
+            },
103
+        )
96 104
     })
97 105
     return profiles
98 106
 }
@@ -100,21 +108,36 @@ const generateDummyProfiles = count => {
100 108
 const generatedSeekers = generateDummyProfiles(100)
101 109
 const generatedProviders = generateDummyProfiles(10)
102 110
 
103
-const compareProfiles = (profile, unorderedPotentialMatches) => {
111
+const scoreMatch = (seeker, potentialMatch) => {
112
+    const seekerResponseValues = seeker.profileResponses.map(res =>
113
+        parseInt(Object.values(res)),
114
+    )
115
+    const potentialMatchResponseValues = potentialMatch.profileResponses.map(
116
+        res => parseInt(Object.values(res)),
117
+    )
118
+    return Math.floor(
119
+        similarity(seekerResponseValues, potentialMatchResponseValues) * magic,
120
+    )
121
+}
122
+const compareProfile = (seeker, unorderedPotentialMatches) => {
104 123
     const scored = unorderedPotentialMatches.map(potentialMatch => {
105
-        // score the match
106
-        const score = rand(1900)
107 124
         // add the match to object keyed by score
108
-        return { score, profile: potentialMatch }
125
+        return {
126
+            profileMatchScore: scoreMatch(seeker, potentialMatch),
127
+            profile: potentialMatch,
128
+        }
109 129
     })
110
-    // create array ordered by score
111
-    const orderedPotentialMatches = scored.sort((a, b) => a.score - b.score)
112
-    return orderedPotentialMatches
130
+    // return ordered by score
131
+    return scored.sort((a, b) => a.profileMatchScore - b.profileMatchScore)
113 132
 }
114 133
 
115 134
 generatedSeekers.forEach(seeker => {
116
-    console.log(compareProfiles(seeker, generatedProviders))
135
+    const matchQueue = compareProfile(seeker, generatedProviders).map(
136
+        provider => ({
137
+            score: provider.profileMatchScore,
138
+            profile_id: provider.profile.id,
139
+        }),
140
+    )
141
+    console.log(`\n---|    Results for job_seeker: ${seeker.id}    |---`)
142
+    console.log(matchQueue)
117 143
 })
118
-// console.log(generatedProviders)
119
-// console.log(generatedSeekers[0].profileResponses)
120
-// console.log(generatedProviders[0].profileResponses)

+ 79
- 0
backend/package-lock.json Vedi File

@@ -17,6 +17,7 @@
17 17
         "@hapipal/confidence": "^6.0.1",
18 18
         "@hapipal/schmervice": "^2.0.0",
19 19
         "@hapipal/schwifty": "^6.0.0",
20
+        "compute-cosine-similarity": "^1.0.0",
20 21
         "dotenv": "^10.0.0",
21 22
         "exiting": "^6.0.1",
22 23
         "hapi-swagger": "^14.1.3",
@@ -2362,6 +2363,35 @@
2362 2363
       "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
2363 2364
       "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
2364 2365
     },
2366
+    "node_modules/compute-cosine-similarity": {
2367
+      "version": "1.0.0",
2368
+      "resolved": "https://registry.npmjs.org/compute-cosine-similarity/-/compute-cosine-similarity-1.0.0.tgz",
2369
+      "integrity": "sha1-KfK/Lnuu+iMcq6QFkaMcF7GaTpU=",
2370
+      "dependencies": {
2371
+        "compute-dot": "^1.1.0",
2372
+        "compute-l2norm": "^1.1.0",
2373
+        "validate.io-array": "^1.0.5",
2374
+        "validate.io-function": "^1.0.2"
2375
+      }
2376
+    },
2377
+    "node_modules/compute-dot": {
2378
+      "version": "1.1.0",
2379
+      "resolved": "https://registry.npmjs.org/compute-dot/-/compute-dot-1.1.0.tgz",
2380
+      "integrity": "sha1-AaW6LHr3O5kAKsslhFnJV2qCMtw=",
2381
+      "dependencies": {
2382
+        "validate.io-array": "^1.0.3",
2383
+        "validate.io-function": "^1.0.2"
2384
+      }
2385
+    },
2386
+    "node_modules/compute-l2norm": {
2387
+      "version": "1.1.0",
2388
+      "resolved": "https://registry.npmjs.org/compute-l2norm/-/compute-l2norm-1.1.0.tgz",
2389
+      "integrity": "sha1-vQkTHGs2yNcMaDNOF2AJpOCpiaw=",
2390
+      "dependencies": {
2391
+        "validate.io-array": "^1.0.3",
2392
+        "validate.io-function": "^1.0.2"
2393
+      }
2394
+    },
2365 2395
     "node_modules/concat-map": {
2366 2396
       "version": "0.0.1",
2367 2397
       "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -7915,6 +7945,16 @@
7915 7945
         "spdx-expression-parse": "^3.0.0"
7916 7946
       }
7917 7947
     },
7948
+    "node_modules/validate.io-array": {
7949
+      "version": "1.0.6",
7950
+      "resolved": "https://registry.npmjs.org/validate.io-array/-/validate.io-array-1.0.6.tgz",
7951
+      "integrity": "sha1-W1osr9j4uFq7L4hroVPy2Tond00="
7952
+    },
7953
+    "node_modules/validate.io-function": {
7954
+      "version": "1.0.2",
7955
+      "resolved": "https://registry.npmjs.org/validate.io-function/-/validate.io-function-1.0.2.tgz",
7956
+      "integrity": "sha1-NDoZgC7TsZaCaceA5VjpNBHAutc="
7957
+    },
7918 7958
     "node_modules/validator": {
7919 7959
       "version": "10.11.0",
7920 7960
       "resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz",
@@ -9946,6 +9986,35 @@
9946 9986
       "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
9947 9987
       "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
9948 9988
     },
9989
+    "compute-cosine-similarity": {
9990
+      "version": "1.0.0",
9991
+      "resolved": "https://registry.npmjs.org/compute-cosine-similarity/-/compute-cosine-similarity-1.0.0.tgz",
9992
+      "integrity": "sha1-KfK/Lnuu+iMcq6QFkaMcF7GaTpU=",
9993
+      "requires": {
9994
+        "compute-dot": "^1.1.0",
9995
+        "compute-l2norm": "^1.1.0",
9996
+        "validate.io-array": "^1.0.5",
9997
+        "validate.io-function": "^1.0.2"
9998
+      }
9999
+    },
10000
+    "compute-dot": {
10001
+      "version": "1.1.0",
10002
+      "resolved": "https://registry.npmjs.org/compute-dot/-/compute-dot-1.1.0.tgz",
10003
+      "integrity": "sha1-AaW6LHr3O5kAKsslhFnJV2qCMtw=",
10004
+      "requires": {
10005
+        "validate.io-array": "^1.0.3",
10006
+        "validate.io-function": "^1.0.2"
10007
+      }
10008
+    },
10009
+    "compute-l2norm": {
10010
+      "version": "1.1.0",
10011
+      "resolved": "https://registry.npmjs.org/compute-l2norm/-/compute-l2norm-1.1.0.tgz",
10012
+      "integrity": "sha1-vQkTHGs2yNcMaDNOF2AJpOCpiaw=",
10013
+      "requires": {
10014
+        "validate.io-array": "^1.0.3",
10015
+        "validate.io-function": "^1.0.2"
10016
+      }
10017
+    },
9949 10018
     "concat-map": {
9950 10019
       "version": "0.0.1",
9951 10020
       "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -14163,6 +14232,16 @@
14163 14232
         "spdx-expression-parse": "^3.0.0"
14164 14233
       }
14165 14234
     },
14235
+    "validate.io-array": {
14236
+      "version": "1.0.6",
14237
+      "resolved": "https://registry.npmjs.org/validate.io-array/-/validate.io-array-1.0.6.tgz",
14238
+      "integrity": "sha1-W1osr9j4uFq7L4hroVPy2Tond00="
14239
+    },
14240
+    "validate.io-function": {
14241
+      "version": "1.0.2",
14242
+      "resolved": "https://registry.npmjs.org/validate.io-function/-/validate.io-function-1.0.2.tgz",
14243
+      "integrity": "sha1-NDoZgC7TsZaCaceA5VjpNBHAutc="
14244
+    },
14166 14245
     "validator": {
14167 14246
       "version": "10.11.0",
14168 14247
       "resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz",

+ 1
- 0
backend/package.json Vedi File

@@ -21,6 +21,7 @@
21 21
     "@hapipal/confidence": "^6.0.1",
22 22
     "@hapipal/schmervice": "^2.0.0",
23 23
     "@hapipal/schwifty": "^6.0.0",
24
+    "compute-cosine-similarity": "^1.0.0",
24 25
     "dotenv": "^10.0.0",
25 26
     "exiting": "^6.0.1",
26 27
     "hapi-swagger": "^14.1.3",

Loading…
Annulla
Salva