|
|
@@ -1,25 +1,14 @@
|
|
1
|
1
|
const fs = require('fs')
|
|
2
|
|
-const cosineSimilarity = require('compute-cosine-similarity')
|
|
3
|
|
-const mockOutputPath = './db/generated/_batch'
|
|
4
|
|
-const magic = 1000
|
|
|
2
|
+const config = require('./config')
|
|
|
3
|
+const random = require('./random')
|
|
|
4
|
+const classes = require('./classes')
|
|
|
5
|
+const score = require('./score')
|
|
5
|
6
|
|
|
6
|
|
-// Insert here how many users you would like to generate:
|
|
7
|
|
-const total = 1000
|
|
8
|
|
-const batchSize = 100
|
|
9
|
7
|
let batchCount = 1 // Counter to track how many things we've generated
|
|
10
|
|
-
|
|
11
|
8
|
let extraProfilesToGenerate = 0
|
|
12
|
9
|
let extraProfileCount = 0 // Counter to track how many EXTRA profiles we've generated
|
|
|
10
|
+let generatedResponseCount = 0 // Counter to track every response generated
|
|
13
|
11
|
|
|
14
|
|
-let generatedResponseCount = 0
|
|
15
|
|
-
|
|
16
|
|
-// Amount of responses for a complete survey
|
|
17
|
|
-const questions = 13
|
|
18
|
|
-
|
|
19
|
|
-// Seekers per 100 profiles
|
|
20
|
|
-const percentageOfSeekers = 90
|
|
21
|
|
-
|
|
22
|
|
-const scoreVals = [100, 140, 180, 220, 260, 400]
|
|
23
|
12
|
// Values for responsess as strings
|
|
24
|
13
|
const possibleResponses = {
|
|
25
|
14
|
not_important: null,
|
|
|
@@ -31,22 +20,17 @@ const possibleResponses = {
|
|
31
|
20
|
}
|
|
32
|
21
|
for (let i = 0; i < Object.keys(possibleResponses).length; i++) {
|
|
33
|
22
|
const key = Object.keys(possibleResponses)[i]
|
|
34
|
|
- possibleResponses[key] = scoreVals[i].toString()
|
|
|
23
|
+ possibleResponses[key] = config.scoreVals[i].toString()
|
|
35
|
24
|
}
|
|
36
|
25
|
|
|
37
|
26
|
/**
|
|
38
|
27
|
* Our initial file setup
|
|
39
|
28
|
*/
|
|
40
|
|
-const header = `/**
|
|
41
|
|
-* GENERATED MOCK SIIMEE DATA
|
|
42
|
|
-* Generated at: ${Date.now()}
|
|
43
|
|
-*/
|
|
44
|
|
-`
|
|
45
|
29
|
const write = async (batchNum, outputDataObject) => {
|
|
46
|
|
- await fs.writeFile(`${mockOutputPath}_${batchNum}.js`, '', () => {})
|
|
|
30
|
+ await fs.writeFile(`${config.mockOutputPath}_${batchNum}.js`, '', () => {})
|
|
47
|
31
|
fs.appendFile(
|
|
48
|
|
- `${mockOutputPath}_${batchNum}.js`,
|
|
49
|
|
- header + 'module.exports = ' + JSON.stringify(outputDataObject),
|
|
|
32
|
+ `${config.mockOutputPath}_${batchNum}.js`,
|
|
|
33
|
+ config.header + 'module.exports = ' + JSON.stringify(outputDataObject),
|
|
50
|
34
|
err => {
|
|
51
|
35
|
if (err) {
|
|
52
|
36
|
console.error(err)
|
|
|
@@ -56,190 +40,44 @@ const write = async (batchNum, outputDataObject) => {
|
|
56
|
40
|
)
|
|
57
|
41
|
}
|
|
58
|
42
|
|
|
59
|
|
-/**
|
|
60
|
|
- * [100, 140, 180, 220, 260, 400]
|
|
61
|
|
- */
|
|
62
|
|
-const preComputedScores = {
|
|
63
|
|
- 100: {
|
|
64
|
|
- 100: 0,
|
|
65
|
|
- 140: 0,
|
|
66
|
|
- 180: 0,
|
|
67
|
|
- 220: 0,
|
|
68
|
|
- 260: 0,
|
|
69
|
|
- 400: 0,
|
|
70
|
|
- },
|
|
71
|
|
- 140: {
|
|
72
|
|
- 100: 0,
|
|
73
|
|
- 140: 0,
|
|
74
|
|
- 180: 0,
|
|
75
|
|
- 220: 0,
|
|
76
|
|
- 260: 0,
|
|
77
|
|
- 400: 0,
|
|
78
|
|
- },
|
|
79
|
|
- 180: {
|
|
80
|
|
- 100: 0,
|
|
81
|
|
- 140: 0,
|
|
82
|
|
- 180: 0,
|
|
83
|
|
- 220: 0,
|
|
84
|
|
- 260: 0,
|
|
85
|
|
- 400: 0,
|
|
86
|
|
- },
|
|
87
|
|
- 220: {
|
|
88
|
|
- 100: 0,
|
|
89
|
|
- 140: 0,
|
|
90
|
|
- 180: 0,
|
|
91
|
|
- 220: 0,
|
|
92
|
|
- 260: 0,
|
|
93
|
|
- 400: 0,
|
|
94
|
|
- },
|
|
95
|
|
- 260: {
|
|
96
|
|
- 100: 0,
|
|
97
|
|
- 140: 0,
|
|
98
|
|
- 180: 0,
|
|
99
|
|
- 220: 0,
|
|
100
|
|
- 260: 0,
|
|
101
|
|
- 400: 0,
|
|
102
|
|
- },
|
|
103
|
|
- 400: {
|
|
104
|
|
- 100: 0,
|
|
105
|
|
- 140: 0,
|
|
106
|
|
- 180: 0,
|
|
107
|
|
- 220: 0,
|
|
108
|
|
- 260: 0,
|
|
109
|
|
- 400: 0,
|
|
110
|
|
- },
|
|
111
|
|
-}
|
|
112
|
|
-const score2d = (a, b) => {
|
|
113
|
|
- const aScorePlusBase = [100]
|
|
114
|
|
- const bScorePlusBase = [100]
|
|
115
|
|
- aScorePlusBase.push(a)
|
|
116
|
|
- bScorePlusBase.push(b)
|
|
117
|
|
- return Math.round(
|
|
118
|
|
- Math.pow(cosineSimilarity(aScorePlusBase, bScorePlusBase), 10) * magic,
|
|
119
|
|
- )
|
|
120
|
|
-}
|
|
121
|
|
-scoreVals.forEach(val => {
|
|
122
|
|
- scoreVals.forEach(v => {
|
|
123
|
|
- preComputedScores[val][v] = score2d(val, v)
|
|
124
|
|
- })
|
|
125
|
|
-})
|
|
126
|
|
-
|
|
127
|
|
-const possibleZipcodes = [
|
|
128
|
|
- '90065', // Glassel
|
|
129
|
|
- '90012', // Chinatown
|
|
130
|
|
- '90240', // Downey
|
|
131
|
|
- '91030', // South Pasadena
|
|
132
|
|
- '91201', // Glendale
|
|
133
|
|
- '91399', // Woodland Hills
|
|
134
|
|
- '91401', // Van Nuys
|
|
135
|
|
- '90840', // Long Beach
|
|
136
|
|
- '91001', // Altadena
|
|
137
|
|
- '91011', // La Canada Flintridge
|
|
138
|
|
- '97075', // Beaverton
|
|
139
|
|
-]
|
|
140
|
|
-
|
|
141
|
43
|
// Helper functions
|
|
142
|
|
-const randomNumber = max => {
|
|
143
|
|
- return Math.floor(Math.random() * max) < 1
|
|
144
|
|
- ? 1
|
|
145
|
|
- : Math.floor(Math.random() * max)
|
|
146
|
|
-}
|
|
147
|
|
-const randomValFrom = arr => arr[randomNumber(arr.length)]
|
|
148
|
|
-const randomEmail = (length = 5) => {
|
|
149
|
|
- let chars =
|
|
150
|
|
- 'abcdefghijklmnopqrstuvwxyz-_abcdefghijklmnopqrstuvwxyz0123456789'
|
|
151
|
|
- let str = ''
|
|
152
|
|
- for (let i = 0; i < length + randomNumber(9); i++) {
|
|
153
|
|
- str += chars.charAt(Math.floor(Math.random() * chars.length))
|
|
154
|
|
- }
|
|
155
|
|
- const suffixs = [
|
|
156
|
|
- '@gmail.com',
|
|
157
|
|
- '@aol.com',
|
|
158
|
|
- '@yahoo.com',
|
|
159
|
|
- '@apple.com',
|
|
160
|
|
- '@hotmail.com',
|
|
161
|
|
- '@rocket-mail.com',
|
|
162
|
|
- '@mail.com',
|
|
163
|
|
- ]
|
|
164
|
|
- return str + randomValFrom(suffixs)
|
|
165
|
|
-}
|
|
166
|
|
-const randomName = (length = 4) => {
|
|
167
|
|
- let chars = 'aeiouaeiouabcdefghijklmnoprstuvwyabcdefghijklmnopqrstuvwxyz'
|
|
168
|
|
- let str = ''
|
|
169
|
|
- for (let i = 0; i < length + randomNumber(9); i++) {
|
|
170
|
|
- str += chars.charAt(Math.floor(Math.random() * chars.length))
|
|
171
|
|
- }
|
|
172
|
|
- return str
|
|
173
|
|
-}
|
|
174
|
|
-
|
|
|
44
|
+// const preComputedScores = score.precomputed
|
|
175
|
45
|
const generate = (classObj, amount, meta) => {
|
|
176
|
46
|
const instances = []
|
|
177
|
47
|
for (let i = 0; i < amount; i++) {
|
|
178
|
|
- let startFrom = meta?.starting ? meta.starting - batchSize : 0
|
|
|
48
|
+ let startFrom = meta?.starting ? meta.starting - config.batchSize : 0
|
|
179
|
49
|
instances.push(new classObj(i + startFrom + 1, meta))
|
|
180
|
50
|
}
|
|
181
|
51
|
return instances
|
|
182
|
52
|
}
|
|
183
|
53
|
|
|
184
|
|
-class User {
|
|
185
|
|
- constructor(id) {
|
|
186
|
|
- this.user_id = id
|
|
187
|
|
- this.user_name = ''
|
|
188
|
|
- this.user_email = ''
|
|
189
|
|
- this.is_admin = false
|
|
190
|
|
- this.is_poster = false
|
|
191
|
|
- }
|
|
192
|
|
-}
|
|
193
|
|
-class Profile {
|
|
194
|
|
- constructor(id, override) {
|
|
195
|
|
- this.user_id = override?.user_id ? override.user_id : id
|
|
196
|
|
- this.profile_id = override?.profile_id ? override.profile_id + id : id
|
|
197
|
|
- }
|
|
198
|
|
-}
|
|
199
|
|
-class Response {
|
|
200
|
|
- constructor(id) {
|
|
201
|
|
- this.response_id = id
|
|
202
|
|
- this.profile_id = null
|
|
203
|
|
- this.response_key_id = null
|
|
204
|
|
- this.val = null
|
|
205
|
|
- }
|
|
206
|
|
-}
|
|
207
|
|
-
|
|
208
|
54
|
console.log('\nStarting...\n---')
|
|
209
|
55
|
|
|
210
|
|
-for (let batch = batchSize; batch <= total; batch += batchSize) {
|
|
211
|
|
- /**
|
|
212
|
|
- * Generate Users
|
|
213
|
|
- */
|
|
214
|
|
- let users = generate(User, batchSize, {
|
|
215
|
|
- starting: batchSize * batchCount,
|
|
|
56
|
+/**
|
|
|
57
|
+ * Generate Users
|
|
|
58
|
+ */
|
|
|
59
|
+const generateUsers = () => {
|
|
|
60
|
+ let users = generate(classes.User, config.batchSize, {
|
|
|
61
|
+ starting: config.batchSize * batchCount,
|
|
216
|
62
|
})
|
|
217
|
63
|
users.forEach(user => {
|
|
218
|
|
- user.is_poster = randomNumber(100) > percentageOfSeekers ? 1 : 0
|
|
|
64
|
+ user.is_poster = random.number(100) > config.percentageOfSeekers ? 1 : 0
|
|
219
|
65
|
if (user.is_poster) {
|
|
220
|
|
- extraProfilesToGenerate = extraProfilesToGenerate + randomNumber(2)
|
|
|
66
|
+ extraProfilesToGenerate = extraProfilesToGenerate + random.number(2)
|
|
221
|
67
|
}
|
|
222
|
|
- user.user_name = randomName() + ' ' + randomName()
|
|
223
|
|
- user.user_email = randomEmail()
|
|
|
68
|
+ user.user_name = random.name() + ' ' + random.name()
|
|
|
69
|
+ user.user_email = random.email()
|
|
224
|
70
|
})
|
|
225
|
|
- let jobPosterIds = users
|
|
226
|
|
- .filter(user => user.is_poster > 0)
|
|
227
|
|
- .map(user => user.user_id)
|
|
228
|
71
|
console.log('COMPLETED: Generated Users...')
|
|
|
72
|
+ return users
|
|
|
73
|
+}
|
|
229
|
74
|
|
|
230
|
|
- // Guarentee ONE job poster
|
|
231
|
|
- if (!jobPosterIds.length) {
|
|
232
|
|
- randomValFrom(users).is_poster = 1
|
|
233
|
|
- jobPosterIds = users
|
|
234
|
|
- .filter(user => user.is_poster > 0)
|
|
235
|
|
- .map(user => user.user_id)
|
|
236
|
|
- }
|
|
237
|
|
-
|
|
238
|
|
- /**
|
|
239
|
|
- * Generate Profiles
|
|
240
|
|
- */
|
|
241
|
|
- let profiles = generate(Profile, batchSize, {
|
|
242
|
|
- starting: batchSize * batchCount,
|
|
|
75
|
+/**
|
|
|
76
|
+ * Generate Profiles
|
|
|
77
|
+ */
|
|
|
78
|
+const generateProfiles = jobPosterIds => {
|
|
|
79
|
+ let profiles = generate(classes.Profile, config.batchSize, {
|
|
|
80
|
+ starting: config.batchSize * batchCount,
|
|
243
|
81
|
profile_id: extraProfileCount,
|
|
244
|
82
|
})
|
|
245
|
83
|
// Generate extra job posting profiles
|
|
|
@@ -248,12 +86,13 @@ for (let batch = batchSize; batch <= total; batch += batchSize) {
|
|
248
|
86
|
if (extraProfilesToGenerate > 0) {
|
|
249
|
87
|
let extras = []
|
|
250
|
88
|
for (let l = 0; l < extraProfilesToGenerate; l++) {
|
|
251
|
|
- const generatedExtraProfiles = generate(Profile, 1, {
|
|
|
89
|
+ const generatedExtraProfiles = generate(classes.Profile, 1, {
|
|
252
|
90
|
user_id:
|
|
253
|
91
|
jobPosterIds.length > 1
|
|
254
|
|
- ? randomValFrom(jobPosterIds)
|
|
|
92
|
+ ? random.valFrom(jobPosterIds)
|
|
255
|
93
|
: jobPosterIds[0],
|
|
256
|
|
- profile_id: batchSize * batchCount + extraProfileCount + l,
|
|
|
94
|
+ profile_id:
|
|
|
95
|
+ config.batchSize * batchCount + extraProfileCount + l,
|
|
257
|
96
|
})
|
|
258
|
97
|
extras = [...extras, ...generatedExtraProfiles]
|
|
259
|
98
|
}
|
|
|
@@ -263,43 +102,67 @@ for (let batch = batchSize; batch <= total; batch += batchSize) {
|
|
263
|
102
|
})
|
|
264
|
103
|
}
|
|
265
|
104
|
console.log('COMPLETED: Generated Profiles...')
|
|
|
105
|
+ return profiles
|
|
|
106
|
+}
|
|
266
|
107
|
|
|
267
|
|
- /**
|
|
268
|
|
- * Generate Responses
|
|
269
|
|
- */
|
|
|
108
|
+/**
|
|
|
109
|
+ * Generate Responses
|
|
|
110
|
+ */
|
|
|
111
|
+const generateResponses = profiles => {
|
|
270
|
112
|
// Generate responses first, before filling in details
|
|
271
|
113
|
let responses = generate(
|
|
272
|
|
- Response,
|
|
273
|
|
- (batchSize + extraProfilesToGenerate) * questions,
|
|
274
|
|
- { starting: generatedResponseCount + batchSize },
|
|
|
114
|
+ classes.Response,
|
|
|
115
|
+ (config.batchSize + extraProfilesToGenerate) * config.questions,
|
|
|
116
|
+ { starting: generatedResponseCount + config.batchSize },
|
|
275
|
117
|
)
|
|
276
|
118
|
profiles.forEach((profile, i) => {
|
|
277
|
|
- const startingIndex = i * questions
|
|
278
|
|
- for (let k = 0; k < questions; k++) {
|
|
|
119
|
+ const startingIndex = i * config.questions
|
|
|
120
|
+ for (let k = 0; k < config.questions; k++) {
|
|
279
|
121
|
const resToEdit = responses[startingIndex + k]
|
|
280
|
122
|
resToEdit.response_key_id = k + 1
|
|
281
|
123
|
resToEdit.profile_id = profile.profile_id
|
|
282
|
124
|
resToEdit.val =
|
|
283
|
|
- k + 1 == questions
|
|
284
|
|
- ? randomValFrom(possibleZipcodes)
|
|
285
|
|
- : randomValFrom(Object.values(possibleResponses))
|
|
|
125
|
+ k + 1 == config.questions
|
|
|
126
|
+ ? random.valFrom(config.possibleZipcodes)
|
|
|
127
|
+ : random.valFrom(Object.values(possibleResponses))
|
|
286
|
128
|
}
|
|
287
|
129
|
})
|
|
288
|
130
|
generatedResponseCount = generatedResponseCount + responses.length
|
|
289
|
131
|
console.log('COMPLETED: Generated Responses...')
|
|
|
132
|
+ return responses
|
|
|
133
|
+}
|
|
|
134
|
+
|
|
|
135
|
+/**
|
|
|
136
|
+ * Our main generator loop
|
|
|
137
|
+ */
|
|
|
138
|
+for (
|
|
|
139
|
+ let batch = config.batchSize;
|
|
|
140
|
+ batch <= config.total;
|
|
|
141
|
+ batch += config.batchSize
|
|
|
142
|
+) {
|
|
|
143
|
+ const users = generateUsers()
|
|
290
|
144
|
|
|
291
|
|
- /**
|
|
292
|
|
- * Our output format
|
|
293
|
|
- */
|
|
294
|
|
- const outputDataObject = { users, profiles, responses }
|
|
295
|
|
- // const outputDataObject = { users, profiles, responses, match_queues }
|
|
296
|
|
- write(batchSize * batchCount, outputDataObject)
|
|
|
145
|
+ let jobPosterIds = users
|
|
|
146
|
+ .filter(user => user.is_poster > 0)
|
|
|
147
|
+ .map(user => user.user_id)
|
|
|
148
|
+ // Guarentee ONE job poster
|
|
|
149
|
+ if (!jobPosterIds.length) {
|
|
|
150
|
+ random.valFrom(users).is_poster = 1
|
|
|
151
|
+ jobPosterIds = users
|
|
|
152
|
+ .filter(user => user.is_poster > 0)
|
|
|
153
|
+ .map(user => user.user_id)
|
|
|
154
|
+ }
|
|
|
155
|
+
|
|
|
156
|
+ const profiles = generateProfiles(jobPosterIds)
|
|
|
157
|
+ const responses = generateResponses(profiles)
|
|
|
158
|
+
|
|
|
159
|
+ write(config.batchSize * batchCount, { users, profiles, responses })
|
|
297
|
160
|
batchCount++
|
|
298
|
161
|
}
|
|
299
|
162
|
|
|
300
|
|
-// /**
|
|
301
|
|
-// * Score all the profiles!
|
|
302
|
|
-// */
|
|
|
163
|
+/**
|
|
|
164
|
+ * Score all the profiles!
|
|
|
165
|
+ */
|
|
303
|
166
|
// const compareProfileResponses = (seeker, potentialMatch) => {
|
|
304
|
167
|
// const checkValCb = res => {
|
|
305
|
168
|
// const val = parseInt(res.val)
|