Skip to content

Commit

Permalink
Merge pull request #315 from cofacts/media-similarity
Browse files Browse the repository at this point in the history
[3] Expose media similarity in ListArticles
  • Loading branch information
MrOrz authored Sep 1, 2023
2 parents e8519e7 + a8cca5a commit 2d3dc48
Show file tree
Hide file tree
Showing 11 changed files with 77 additions and 12 deletions.
3 changes: 3 additions & 0 deletions src/__tests__/__snapshots__/auth.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
exports[`verifyProfile authenticates user via profile ID 1`] = `
Object {
"_cursor": undefined,
"_fields": undefined,
"_score": 0.2876821,
"email": "[email protected]",
"facebookId": "secret-fb-id",
Expand All @@ -16,6 +17,7 @@ Object {
exports[`verifyProfile authenticates user via same email of existing user; also updates profile ID 1`] = `
Object {
"_cursor": undefined,
"_fields": undefined,
"_score": undefined,
"email": "[email protected]",
"facebookId": "secret-fb-id",
Expand All @@ -31,6 +33,7 @@ Object {
exports[`verifyProfile creates new user if user does not exist 1`] = `
Object {
"_cursor": undefined,
"_fields": undefined,
"_score": undefined,
"avatarUrl": "url-to-photo",
"createdAt": "1989-06-04T00:00:00.000Z",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
exports[`userLoaderFactory should return correct user with given slug 1`] = `
Object {
"_cursor": undefined,
"_fields": undefined,
"_score": 0.6931472,
"email": "[email protected]",
"highlight": undefined,
Expand All @@ -16,6 +17,7 @@ Object {
exports[`userLoaderFactory should return correct user with given slug 2`] = `
Object {
"_cursor": undefined,
"_fields": undefined,
"_score": 0.6931472,
"email": "[email protected]",
"highlight": undefined,
Expand Down
13 changes: 12 additions & 1 deletion src/graphql/models/Article.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
GraphQLInt,
GraphQLBoolean,
GraphQLEnumType,
GraphQLFloat,
} from 'graphql';

import {
Expand Down Expand Up @@ -548,7 +549,17 @@ const Article = new GraphQLObjectType({

export const ArticleConnection = createConnectionType(
'ArticleConnection',
Article
Article,
{
extraEdgeFields: {
mediaSimilarity: {
type: new GraphQLNonNull(GraphQLFloat),
description: `The search hit's similarity with provided mediaUrl.
Ranges from 0 to 1. 0 if mediaUrl is not provided, or the hit is not matched by mediaUrl.`,
resolve: ({ node }) => node._fields?.mediaSimilarity?.[0] ?? 0,
},
},
}
);

export default Article;
3 changes: 3 additions & 0 deletions src/graphql/models/__tests__/__snapshots__/User.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
exports[`User model userFieldResolver returns the right backend user given appUserId 1`] = `
Object {
"_cursor": undefined,
"_fields": undefined,
"_score": undefined,
"appId": "TEST_BACKEND",
"appUserId": "userTest1",
Expand All @@ -16,6 +17,7 @@ Object {
exports[`User model userFieldResolver returns the right backend user given db userId 1`] = `
Object {
"_cursor": undefined,
"_fields": undefined,
"_score": undefined,
"appId": "TEST_BACKEND",
"appUserId": "userTest1",
Expand All @@ -29,6 +31,7 @@ Object {
exports[`User model userFieldResolver returns the right web user given userId 1`] = `
Object {
"_cursor": undefined,
"_fields": undefined,
"_score": undefined,
"appId": "WEBSITE",
"highlight": undefined,
Expand Down
23 changes: 22 additions & 1 deletion src/graphql/queries/ListArticles.js
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,14 @@ export default {
}

const body = {
// Source fields are disabled when `script_fields` presets.
// Ref: https://www.elastic.co/guide/en/elasticsearch/reference/6.8/search-request-source-filtering.html
// https://discuss.elastic.co/t/script-field-along-with-all-the-other-fields-using-painless/296384/2
// We need to turn _source back on.
//
_source: true,
script_fields: {},

sort: getSortArgs(orderBy, {
replyCount: o => ({ normalArticleReplyCount: { order: o } }),
lastRepliedAt: o => ({
Expand Down Expand Up @@ -580,6 +588,15 @@ export default {
return map;
}, {});

body.script_fields.mediaSimilarity = {
script: {
lang: 'painless',
// Note: params.similarityMap.get(doc['attachmentHash'].value) may be null if no attahmentHash, or when attahmentHash not in similarityMap.
source: `doc.containsKey('attachmentHash') ? params.similarityMap.get(doc['attachmentHash'].value) : null`,
params: { similarityMap },
},
};

// Make media search dominant text search
const MULTIPLIER = 100;

Expand All @@ -596,8 +613,12 @@ export default {
script_score: {
script: {
lang: 'painless',
params: { similarityMap },
// Every hit in this query is inside similarityMap, no need for null handling.
//
// `mediaSimilarity` cannot be used here because it only exists after search complete.
//
source: `${MULTIPLIER} * params.similarityMap.get(doc['attachmentHash'].value)`,
params: { similarityMap },
},
},
},
Expand Down
6 changes: 6 additions & 0 deletions src/graphql/queries/__tests__/ListArticles.js
Original file line number Diff line number Diff line change
Expand Up @@ -990,6 +990,7 @@ describe('ListArticles', () => {
) {
edges {
score
mediaSimilarity
node {
id
articleType
Expand All @@ -1006,6 +1007,7 @@ describe('ListArticles', () => {
"ListArticles": Object {
"edges": Array [
Object {
"mediaSimilarity": 1,
"node": Object {
"articleType": "IMAGE",
"attachmentHash": "ffff8000",
Expand All @@ -1015,6 +1017,7 @@ describe('ListArticles', () => {
"score": 100,
},
Object {
"mediaSimilarity": 0.5,
"node": Object {
"articleType": "IMAGE",
"attachmentHash": "ffff8001",
Expand All @@ -1024,6 +1027,7 @@ describe('ListArticles', () => {
"score": 60.03248,
},
Object {
"mediaSimilarity": 0,
"node": Object {
"articleType": "TEXT",
"attachmentHash": "",
Expand Down Expand Up @@ -1139,6 +1143,7 @@ describe('ListArticles', () => {
) {
edges {
score
mediaSimilarity
node {
id
articleType
Expand All @@ -1164,6 +1169,7 @@ describe('ListArticles', () => {
<HIGHLIGHT>微之</HIGHLIGHT>,<HIGHLIGHT>微之</HIGHLIGHT>!<HIGHLIGHT>此夕此心</HIGHLIGHT>,<HIGHLIGHT>君知之乎</HIGHLIGHT>!
",
},
"mediaSimilarity": 0,
"node": Object {
"articleType": "TEXT",
"attachmentHash": "",
Expand Down
24 changes: 14 additions & 10 deletions src/graphql/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -222,16 +222,18 @@ async function defaultResolveTotalCount({
after, // eslint-disable-line no-unused-vars
...searchContext
}) {
return (await client.count({
...searchContext,
body: {
...searchContext.body,

// totalCount cannot support these
sort: undefined,
track_scores: undefined,
},
})).body.count;
try {
return (await client.count({
...searchContext,
body: {
// count API only supports "query"
query: searchContext.body.query,
},
})).body.count;
} catch (e) /* istanbul ignore next */ {
console.error('[defaultResolveTotalCount]', JSON.stringify(e));
throw e;
}
}

export async function defaultResolveEdges(
Expand Down Expand Up @@ -368,6 +370,7 @@ export function createConnectionType(
resolveLastCursor = defaultResolveLastCursor,
resolveFirstCursor = defaultResolveFirstCursor,
resolveHighlights = defaultResolveHighlights,
extraEdgeFields = {},
} = {}
) {
return new GraphQLObjectType({
Expand Down Expand Up @@ -395,6 +398,7 @@ export function createConnectionType(
type: Highlights,
resolve: resolveHighlights,
},
...extraEdgeFields,
},
})
)
Expand Down
6 changes: 6 additions & 0 deletions src/scripts/__tests__/__snapshots__/cleanupUrls.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ exports[`should clean up urls 1`] = `
Array [
Object {
"_cursor": undefined,
"_fields": undefined,
"_score": 1,
"highlight": undefined,
"id": "new-url",
"inner_hits": undefined,
},
Object {
"_cursor": undefined,
"_fields": undefined,
"_score": 1,
"highlight": undefined,
"id": "url-processed",
Expand All @@ -19,6 +21,7 @@ Array [
},
Object {
"_cursor": undefined,
"_fields": undefined,
"_score": 1,
"highlight": undefined,
"id": "url-foo",
Expand All @@ -27,6 +30,7 @@ Array [
},
Object {
"_cursor": undefined,
"_fields": undefined,
"_score": 1,
"highlight": undefined,
"id": "curl-foo",
Expand All @@ -35,6 +39,7 @@ Array [
},
Object {
"_cursor": undefined,
"_fields": undefined,
"_score": 1,
"highlight": undefined,
"id": "url-bar",
Expand All @@ -43,6 +48,7 @@ Array [
},
Object {
"_cursor": undefined,
"_fields": undefined,
"_score": 1,
"highlight": undefined,
"id": "curl-bar",
Expand Down
2 changes: 2 additions & 0 deletions src/util/__tests__/__snapshots__/scrapUrls.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Array [
"_cursor": Array [
1485907200000,
],
"_fields": undefined,
"_score": null,
"canonical": "http://example.com/article/1111",
"fetchedAt": "2017-02-01T00:00:00.000Z",
Expand All @@ -22,6 +23,7 @@ Array [
"_cursor": Array [
1485907200000,
],
"_fields": undefined,
"_score": null,
"canonical": "http://example.com/article/1111",
"fetchedAt": "2017-02-01T00:00:00.000Z",
Expand Down
4 changes: 4 additions & 0 deletions src/util/__tests__/__snapshots__/user.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
exports[`user utils CreateOrUpdateUser creates backend user if not existed 1`] = `
Object {
"_cursor": undefined,
"_fields": undefined,
"_score": undefined,
"appId": "TEST_BACKEND",
"appUserId": "testUser2",
Expand Down Expand Up @@ -34,6 +35,7 @@ Object {
exports[`user utils CreateOrUpdateUser fills appId for website users 1`] = `
Object {
"_cursor": undefined,
"_fields": undefined,
"_score": undefined,
"appId": "WEBSITE",
"highlight": undefined,
Expand All @@ -47,6 +49,7 @@ Object {
exports[`user utils CreateOrUpdateUser logs error if collision occurs 1`] = `
Object {
"_cursor": undefined,
"_fields": undefined,
"_score": undefined,
"appId": "TEST_BACKEND",
"appUserId": "testUser1",
Expand Down Expand Up @@ -78,6 +81,7 @@ Array [
exports[`user utils CreateOrUpdateUser updates backend users' last active time if user already existed 1`] = `
Object {
"_cursor": undefined,
"_fields": undefined,
"_score": undefined,
"appId": "TEST_BACKEND",
"appUserId": "testUser1",
Expand Down
3 changes: 3 additions & 0 deletions src/util/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export function processMeta({
inner_hits, // nested query search result highlighting.

sort, // cursor when sorted

fields, // scripted fields (if any)
}) {
if (found || _score !== undefined) {
return {
Expand All @@ -28,6 +30,7 @@ export function processMeta({
_score,
highlight,
inner_hits,
_fields: fields,
};
}
return null; // not found
Expand Down

0 comments on commit 2d3dc48

Please sign in to comment.