Compute recommendation scores from updateUserFeed
This commit is contained in:
parent
43a0fc6581
commit
f008971bd1
|
@ -142,36 +142,18 @@ export const getWordScores = (
|
||||||
return normalizedWordScores
|
return normalizedWordScores
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getContractScores(
|
export function getContractScore(
|
||||||
contracts: Contract[],
|
contract: Contract,
|
||||||
wordScores: { [word: string]: number }
|
wordScores: { [word: string]: number }
|
||||||
) {
|
) {
|
||||||
const scorePairs = contracts.map((contract) => {
|
const wordFrequency = contractToWordFrequency(contract)
|
||||||
const wordFrequency = contractToWordFrequency(contract)
|
const score = _.sumBy(Object.keys(wordFrequency), (word) => {
|
||||||
|
const wordFreq = wordFrequency[word] ?? 0
|
||||||
const score = _.sumBy(Object.keys(wordFrequency), (word) => {
|
const weight = wordScores[word] ?? 0
|
||||||
const wordFreq = wordFrequency[word] ?? 0
|
return wordFreq * weight
|
||||||
const weight = wordScores[word] ?? 0
|
|
||||||
return wordFreq * weight
|
|
||||||
})
|
|
||||||
|
|
||||||
return [contract, score] as [Contract, number]
|
|
||||||
})
|
})
|
||||||
|
|
||||||
/*
|
return score
|
||||||
const questionPairs = _.sortBy(
|
|
||||||
scorePairs.map(
|
|
||||||
([contract, score]) => [contract.question, score] as [string, number]
|
|
||||||
),
|
|
||||||
([, score]) => -score
|
|
||||||
)
|
|
||||||
|
|
||||||
console.log('score', questionPairs.slice(0, 100), questionPairs.slice(-100))
|
|
||||||
*/
|
|
||||||
|
|
||||||
return _.fromPairs(
|
|
||||||
scorePairs.map(([contract, score]) => [contract.id, score])
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Caluculate Term Frequency-Inverse Document Frequency (TF-IDF):
|
// Caluculate Term Frequency-Inverse Document Frequency (TF-IDF):
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { getValues } from '../utils'
|
||||||
import { User } from '../../../common/user'
|
import { User } from '../../../common/user'
|
||||||
import { batchedWaitAll } from '../../../common/util/promise'
|
import { batchedWaitAll } from '../../../common/util/promise'
|
||||||
import { Contract } from '../../../common/contract'
|
import { Contract } from '../../../common/contract'
|
||||||
import { updateUserRecommendations } from '../update-recommendations'
|
import { updateWordScores } from '../update-recommendations'
|
||||||
import {
|
import {
|
||||||
getFeedContracts,
|
getFeedContracts,
|
||||||
updateFeed as updateUserFeed,
|
updateFeed as updateUserFeed,
|
||||||
|
@ -23,13 +23,13 @@ async function updateFeed() {
|
||||||
const feedContracts = await getFeedContracts()
|
const feedContracts = await getFeedContracts()
|
||||||
const users = await getValues<User>(
|
const users = await getValues<User>(
|
||||||
firestore.collection('users')
|
firestore.collection('users')
|
||||||
//.where('username', '==', 'JamesGrugett')
|
// .where('username', '==', 'JamesGrugett')
|
||||||
)
|
)
|
||||||
|
|
||||||
await batchedWaitAll(
|
await batchedWaitAll(
|
||||||
users.map((user) => async () => {
|
users.map((user) => async () => {
|
||||||
console.log('Updating recs for', user.username)
|
console.log('Updating recs for', user.username)
|
||||||
await updateUserRecommendations(user, contracts)
|
await updateWordScores(user, contracts)
|
||||||
console.log('Updating feed for', user.username)
|
console.log('Updating feed for', user.username)
|
||||||
await updateUserFeed(user, feedContracts)
|
await updateUserFeed(user, feedContracts)
|
||||||
})
|
})
|
||||||
|
|
|
@ -7,10 +7,7 @@ import { Contract } from '../../common/contract'
|
||||||
import { Bet } from '../../common/bet'
|
import { Bet } from '../../common/bet'
|
||||||
import { User } from '../../common/user'
|
import { User } from '../../common/user'
|
||||||
import { ClickEvent } from '../../common/tracking'
|
import { ClickEvent } from '../../common/tracking'
|
||||||
import {
|
import { getWordScores } from '../../common/recommended-contracts'
|
||||||
getContractScores,
|
|
||||||
getWordScores,
|
|
||||||
} from '../../common/recommended-contracts'
|
|
||||||
import { batchedWaitAll } from '../../common/util/promise'
|
import { batchedWaitAll } from '../../common/util/promise'
|
||||||
|
|
||||||
const firestore = admin.firestore()
|
const firestore = admin.firestore()
|
||||||
|
@ -25,14 +22,11 @@ export const updateRecommendations = functions.pubsub
|
||||||
const users = await getValues<User>(firestore.collection('users'))
|
const users = await getValues<User>(firestore.collection('users'))
|
||||||
|
|
||||||
await batchedWaitAll(
|
await batchedWaitAll(
|
||||||
users.map((user) => () => updateUserRecommendations(user, contracts))
|
users.map((user) => () => updateWordScores(user, contracts))
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
export const updateUserRecommendations = async (
|
export const updateWordScores = async (user: User, contracts: Contract[]) => {
|
||||||
user: User,
|
|
||||||
contracts: Contract[]
|
|
||||||
) => {
|
|
||||||
const [bets, viewCounts, clicks] = await Promise.all([
|
const [bets, viewCounts, clicks] = await Promise.all([
|
||||||
getValues<Bet>(
|
getValues<Bet>(
|
||||||
firestore.collectionGroup('bets').where('userId', '==', user.id)
|
firestore.collectionGroup('bets').where('userId', '==', user.id)
|
||||||
|
@ -50,11 +44,9 @@ export const updateUserRecommendations = async (
|
||||||
])
|
])
|
||||||
|
|
||||||
const wordScores = getWordScores(contracts, viewCounts ?? {}, clicks, bets)
|
const wordScores = getWordScores(contracts, viewCounts ?? {}, clicks, bets)
|
||||||
const contractScores = getContractScores(contracts, wordScores)
|
|
||||||
|
|
||||||
const cachedCollection = firestore.collection(
|
const cachedCollection = firestore.collection(
|
||||||
`private-users/${user.id}/cache`
|
`private-users/${user.id}/cache`
|
||||||
)
|
)
|
||||||
await cachedCollection.doc('wordScores').set(wordScores)
|
await cachedCollection.doc('wordScores').set(wordScores)
|
||||||
await cachedCollection.doc('contractScores').set(contractScores)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import { Bet } from '../../common/bet'
|
||||||
import { Comment } from '../../common/comment'
|
import { Comment } from '../../common/comment'
|
||||||
import { User } from '../../common/user'
|
import { User } from '../../common/user'
|
||||||
import { batchedWaitAll } from '../../common/util/promise'
|
import { batchedWaitAll } from '../../common/util/promise'
|
||||||
|
import { getContractScore } from '../../common/recommended-contracts'
|
||||||
|
|
||||||
const firestore = admin.firestore()
|
const firestore = admin.firestore()
|
||||||
|
|
||||||
|
@ -59,27 +60,17 @@ export const updateFeed = async (user: User, contracts: Contract[]) => {
|
||||||
const userCacheCollection = firestore.collection(
|
const userCacheCollection = firestore.collection(
|
||||||
`private-users/${user.id}/cache`
|
`private-users/${user.id}/cache`
|
||||||
)
|
)
|
||||||
const [recommendationScores, lastViewedTime] = await Promise.all([
|
const [wordScores, lastViewedTime] = await Promise.all([
|
||||||
getValue<{ [contractId: string]: number }>(
|
getValue<{ [word: string]: number }>(userCacheCollection.doc('wordScores')),
|
||||||
userCacheCollection.doc('contractScores')
|
|
||||||
),
|
|
||||||
getValue<{ [contractId: string]: number }>(
|
getValue<{ [contractId: string]: number }>(
|
||||||
userCacheCollection.doc('lastViewTime')
|
userCacheCollection.doc('lastViewTime')
|
||||||
),
|
),
|
||||||
]).then((dicts) => dicts.map((dict) => dict ?? {}))
|
]).then((dicts) => dicts.map((dict) => dict ?? {}))
|
||||||
|
|
||||||
const averageRecScore =
|
|
||||||
1 +
|
|
||||||
_.sumBy(
|
|
||||||
contracts.filter((c) => recommendationScores[c.id] !== undefined),
|
|
||||||
(c) => recommendationScores[c.id]
|
|
||||||
) /
|
|
||||||
(contracts.length + 1)
|
|
||||||
|
|
||||||
const scoredContracts = contracts.map((contract) => {
|
const scoredContracts = contracts.map((contract) => {
|
||||||
const score = scoreContract(
|
const score = scoreContract(
|
||||||
contract,
|
contract,
|
||||||
recommendationScores[contract.id] ?? averageRecScore,
|
wordScores,
|
||||||
lastViewedTime[contract.id]
|
lastViewedTime[contract.id]
|
||||||
)
|
)
|
||||||
return [contract, score] as [Contract, number]
|
return [contract, score] as [Contract, number]
|
||||||
|
@ -105,12 +96,13 @@ export const updateFeed = async (user: User, contracts: Contract[]) => {
|
||||||
|
|
||||||
function scoreContract(
|
function scoreContract(
|
||||||
contract: Contract,
|
contract: Contract,
|
||||||
recommendationScore: number,
|
wordScores: { [word: string]: number },
|
||||||
viewTime: number | undefined
|
viewTime: number | undefined
|
||||||
) {
|
) {
|
||||||
const lastViewedScore = getLastViewedScore(viewTime)
|
const recommendationScore = getContractScore(contract, wordScores)
|
||||||
const activityScore = getActivityScore(contract, viewTime)
|
const activityScore = getActivityScore(contract, viewTime)
|
||||||
return recommendationScore * lastViewedScore * activityScore
|
const lastViewedScore = getLastViewedScore(viewTime)
|
||||||
|
return recommendationScore * activityScore * lastViewedScore
|
||||||
}
|
}
|
||||||
|
|
||||||
function getActivityScore(contract: Contract, viewTime: number | undefined) {
|
function getActivityScore(contract: Contract, viewTime: number | undefined) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user