From 08fc09a39332318b0e91bccf9a62a89912d5bf5e Mon Sep 17 00:00:00 2001 From: Wesley Walser Date: Wed, 15 Dec 2021 16:58:42 +1100 Subject: [PATCH] feat: thread featureScore, neuralScore and featureScoreWeight through from query responses --- package.json | 2 +- src/index.ts | 23 +++++++++++++++-- src/user-agent.ts | 2 +- test/index.test.ts | 63 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 86 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index c26a44c..7e5d9b4 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@sajari/sdk-js", "description": "Sajari JavaScript SDK", - "version": "2.7.0", + "version": "2.8.0", "main": "dist/index.js", "umd:main": "dist/sajarisdk.umd.production.js", "module": "dist/sajarisdk.esm.production.js", diff --git a/src/index.ts b/src/index.ts index 78e156d..50ede1b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -436,7 +436,7 @@ class QueryPipeline extends EventEmitter { } const results: Result[] = (jsonProto.searchResponse?.results || []).map( - ({ indexScore, score, values }, index) => { + ({ indexScore, score, values, neuralScore, featureScore }, index) => { let t: Token | undefined = undefined; const token = (jsonProto.tokens || [])[index]; if (token !== undefined) { @@ -472,6 +472,8 @@ class QueryPipeline extends EventEmitter { values: processProtoValues(values), token: t, promotionPinned, + ...(neuralScore && { neuralScore }), + ...(featureScore && { featureScore }), }; } ); @@ -501,6 +503,7 @@ class QueryPipeline extends EventEmitter { aggregateFilters: aggregateFilters, redirects: redirects, activePromotions: activePromotions, + featureScoreWeight: jsonProto.searchResponse?.featureScoreWeight || 0, }, jsonProto.values || {}, ]; @@ -542,17 +545,30 @@ export interface SearchResponse { * All Promotions activated by the current query (see [[ActivePromotion]]). */ activePromotions: ActivePromotion[]; + + /** + * Feature score weight determines the weighting of featureScore vs neural and index scores. + */ + featureScoreWeight: number; } export interface Result { /** - * indexScore is the index-matched score of this Result. + * indexScore is the index-matched score of this [[Result]]. */ indexScore: number; /** * score is the overall score of this [[Result]]. */ score: number; + /** + * neuralScore is the neural score of this [[Result]]. + */ + neuralScore?: number; + /** + * featureScore is the feature based search score of this [[Result]]. + */ + featureScore?: number; /** * values is an object of field-value pairs. */ @@ -653,6 +669,7 @@ export interface SearchResponseProto { results: ResultProto[]; aggregates: AggregatesProto; aggregateFilters: AggregatesProto; + featureScoreWeight?: number; }>; tokens?: TokenProto[]; values?: Record; @@ -721,6 +738,8 @@ function valueFromProto(value: ValueProto): string | string[] | null { */ interface ResultProto { indexScore: number; + neuralScore?: number; + featureScore?: number; score: number; values: Record; } diff --git a/src/user-agent.ts b/src/user-agent.ts index cf1dab8..e4d9622 100644 --- a/src/user-agent.ts +++ b/src/user-agent.ts @@ -16,6 +16,6 @@ if (scriptTag) { * user agent of sdk * @hidden */ -export const USER_AGENT = ["sajari-sdk-js/2.7.0", suffix] +export const USER_AGENT = ["sajari-sdk-js/2.8.0", suffix] .filter(Boolean) .join(" "); diff --git a/test/index.test.ts b/test/index.test.ts index c7bca1f..d76e536 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -65,6 +65,7 @@ describe("Pipeline", () => { aggregateFilters: {}, redirects: {}, activePromotions: [], + featureScoreWeight: 0, }); expect(fetchMock.mock.calls.length).toEqual(1); @@ -109,6 +110,7 @@ describe("Pipeline", () => { }, }, activePromotions: [], + featureScoreWeight: 0, }); expect(fetchMock.mock.calls.length).toEqual(1); @@ -161,6 +163,7 @@ describe("Pipeline", () => { aggregateFilters: {}, redirects: {}, activePromotions: [], + featureScoreWeight: 0, }); }); @@ -236,6 +239,7 @@ describe("Pipeline", () => { aggregates: {}, aggregateFilters: {}, redirects: {}, + featureScoreWeight: 0, activePromotions: [ { activeExclusions: [], @@ -379,6 +383,7 @@ describe("Pipeline", () => { aggregates: {}, aggregateFilters: {}, redirects: {}, + featureScoreWeight: 0, activePromotions: [ { activeExclusions: [], @@ -421,4 +426,62 @@ describe("Pipeline", () => { "test.com/sajari.api.pipeline.v1.Query/Search" ); }); + + it("search with neural and feature scores", async () => { + const responseObj: SearchResponseProto = { + searchResponse: { + time: "0.003s", + totalResults: "1", + featureScoreWeight: 0.2, + results: [ + { + indexScore: 1, + score: 0.4649218, + neuralScore: 0.333, + featureScore: 0.6666, + values: { + title: { + single: "the result", + }, + }, + }, + ], + }, + }; + fetchMock.mockResponseOnce(JSON.stringify(responseObj)); + + const session = new DefaultSession(TrackingType.None, "url"); + const [response, values] = await client + .pipeline("test", "test") + .search({ q: "hello" }, session.next()); + + expect(values).toEqual({}); + expect(response).toStrictEqual({ + time: 0.003, + totalResults: 1, + results: [ + { + indexScore: 1, + score: 0.4649218, + promotionPinned: false, + token: undefined, + neuralScore: 0.333, + featureScore: 0.6666, + values: { + title: "the result", + }, + }, + ], + aggregates: {}, + aggregateFilters: {}, + activePromotions: [], + redirects: {}, + featureScoreWeight: 0.2, + }); + + expect(fetchMock.mock.calls.length).toEqual(1); + expect(fetchMock.mock.calls[0][0]).toEqual( + "test.com/sajari.api.pipeline.v1.Query/Search" + ); + }); });