diff --git a/.gitignore b/.gitignore index cdb1c753..e4be0b78 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ .DS_Store *.pem db.sql +test.sql # debug npm-debug.log* diff --git a/api/resolvers/notifications.js b/api/resolvers/notifications.js index 4f106f04..a6e000e2 100644 --- a/api/resolvers/notifications.js +++ b/api/resolvers/notifications.js @@ -110,7 +110,7 @@ export default { JOIN "ItemAct" ON "ItemAct"."itemId" = "Item".id WHERE "ItemAct"."userId" <> $1 AND "ItemAct".created_at <= $2 - AND "ItemAct".act <> 'BOOST' + AND "ItemAct".act in ('VOTE', 'TIP') AND "Item"."userId" = $1 GROUP BY "Item".id ORDER BY "sortTime" DESC diff --git a/prisma/migrations/20220630170204_upvote_trust/migration.sql b/prisma/migrations/20220630170204_upvote_trust/migration.sql new file mode 100644 index 00000000..a2fb183e --- /dev/null +++ b/prisma/migrations/20220630170204_upvote_trust/migration.sql @@ -0,0 +1,25 @@ +-- AlterTable +ALTER TABLE "users" ADD COLUMN "upvoteTrust" DOUBLE PRECISION NOT NULL DEFAULT 0; + +CREATE OR REPLACE FUNCTION confidence(successes FLOAT, trials FLOAT, z FLOAT) +RETURNS FLOAT +LANGUAGE plpgsql +AS $$ +DECLARE + p FLOAT; + lhand FLOAT; + rhand FLOAT; + under FLOAT; +BEGIN + IF trials = 0 THEN + RETURN 0; + END IF; + + p := successes / trials; + lhand := p + 1 / (2 * trials) * z * z; + rhand := z * sqrt(p * (1 - p) / trials + z * z / (4 * trials * trials)); + under := 1 + 1 / trials * z * z; + + RETURN (lhand - rhand) / under; +END; +$$; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 23f6f48d..bca8d0c4 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -38,6 +38,7 @@ model User { tipDefault Int @default(10) pubkey String? @unique trust Float @default(0) + upvoteTrust Float @default(0) lastSeenAt DateTime? lastCheckedJobs DateTime? photoId Int? diff --git a/worker/confidence.js b/worker/confidence.js new file mode 100644 index 00000000..d56b4b83 --- /dev/null +++ b/worker/confidence.js @@ -0,0 +1,25 @@ +// https://en.wikipedia.org/wiki/Normal_distribution#Quantile_function +// const z = 1.281551565545 // 80% confidence +// const z = 1.644853626951 // 90% confidence +// const z = 1.959963984540 // 95% confidence +const z = 3.090232306168 // 98% confidence + +function confidence (s, n) { + if (n === 0) { + return 0 + } + + const p = s / n + const left = p + 1 / (2 * n) * z * z + const right = z * Math.sqrt(p * (1 - p) / n + z * z / (4 * n * n)) + const under = 1 + 1 / n * z * z + + return (left - right) / under +} + +console.log(confidence(process.argv[2], process.argv[3])) + +/* + Need to describe how they'll earn + If we trust upvotes how can we use that to determine the best +*/ diff --git a/worker/trust.js b/worker/trust.js index 127d5523..eb2d0e07 100644 --- a/worker/trust.js +++ b/worker/trust.js @@ -12,6 +12,8 @@ function trust ({ boss, models }) { // only explore a path up to this depth from start const MAX_DEPTH = 6 const MAX_TRUST = 0.9 +// https://en.wikipedia.org/wiki/Normal_distribution#Quantile_function +const Z_CONFIDENCE = 2.326347874041 // 98% confidence function pathsOverlap (arr1 = [], arr2 = []) { const dp = new Array(arr1.length + 1).fill(0).map(() => new Array(arr2.length + 1).fill(0)) @@ -135,6 +137,7 @@ function trustGivenGraph (graph, start) { } /* + OLD TRUST GRAPH graph is returned as json in adjacency list where edges are the trust value 0-.9 graph = { node1 : [{node : node2, trust: trust12}, {node: node3, trust: trust13}], @@ -142,20 +145,57 @@ function trustGivenGraph (graph, start) { node3 : [{node : node2, trust: trust32}], } */ +// async function getGraph (models) { +// const [{ graph }] = await models.$queryRaw` +// select json_object_agg(id, hops) as graph +// from ( +// select id, json_agg(json_build_object('node', oid, 'trust', trust)) as hops +// from ( +// select "ItemAct"."userId" as id, "Item"."userId" as oid, least(${MAX_TRUST}, +// sum(POWER(.99, EXTRACT(DAY FROM (NOW_UTC() - "ItemAct".created_at))))/21.0) as trust +// from "ItemAct" +// join "Item" on "itemId" = "Item".id and "ItemAct"."userId" <> "Item"."userId" +// where "ItemAct".act = 'VOTE' group by "ItemAct"."userId", "Item"."userId" +// ) a +// group by id +// ) b` +// return graph +// } + +// upvote confidence graph async function getGraph (models) { const [{ graph }] = await models.$queryRaw` select json_object_agg(id, hops) as graph from ( select id, json_agg(json_build_object('node', oid, 'trust', trust)) as hops from ( - select "ItemAct"."userId" as id, "Item"."userId" as oid, least(${MAX_TRUST}, - sum(POWER(.99, EXTRACT(DAY FROM (NOW_UTC() - "ItemAct".created_at))))/21.0) as trust - from "ItemAct" - join "Item" on "itemId" = "Item".id and "ItemAct"."userId" <> "Item"."userId" - where "ItemAct".act = 'VOTE' group by "ItemAct"."userId", "Item"."userId" - ) a - group by id - ) b` + select s.id, s.oid, confidence(s.shared, count(*), ${Z_CONFIDENCE}) as trust + from ( + select a."userId" as id, b."userId" as oid, count(*) as shared + from "ItemAct" b + join users bu on bu.id = b."userId" + join "ItemAct" a on b."itemId" = a."itemId" + join users au on au.id = a."userId" + join "Item" on "Item".id = b."itemId" + where b.act = 'VOTE' + and a.act = 'VOTE' + and "Item"."parentId" is null + and "Item"."userId" <> b."userId" + and "Item"."userId" <> a."userId" + and b."userId" <> a."userId" + and "Item".created_at >= au.created_at and "Item".created_at >= bu.created_at + group by b."userId", a."userId") s + join users u on s.id = u.id + join users ou on s.oid = ou.id + join "ItemAct" on "ItemAct"."userId" = s.oid + join "Item" on "Item".id = "ItemAct"."itemId" + where "ItemAct".act = 'VOTE' and "Item"."parentId" is null + and "Item"."userId" <> s.oid and "Item"."userId" <> s.id + and "Item".created_at >= u.created_at and "Item".created_at >= ou.created_at + group by s.id, s.oid, s.shared + ) a + group by id + ) b` return graph }