-
Notifications
You must be signed in to change notification settings - Fork 46
feat(answers): add findAnswers
#804
Changes from 7 commits
08b0ecd
c835ae1
54509fe
e1c783f
de96b4a
4f3f07f
ca88e3b
da8af13
2433fb1
7bec235
5aa1206
761e2fd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,8 @@ var requestBuilder = require('./requestBuilder'); | |
var events = require('events'); | ||
var inherits = require('./functions/inherits'); | ||
var objectHasKeys = require('./functions/objectHasKeys'); | ||
var omit = require('./functions/omit'); | ||
var merge = require('./functions/merge'); | ||
|
||
var version = require('./version'); | ||
|
||
|
@@ -248,6 +250,75 @@ AlgoliaSearchHelper.prototype.searchOnce = function(options, cb) { | |
}); | ||
}; | ||
|
||
/** | ||
* @typedef Answer | ||
* @type {object} | ||
* @property {string} extract the extracted value with highlights | ||
* @property {string} extractAttribute the attribute used to extract the answer | ||
* @property {number} score the score indicating how well it was matched | ||
*/ | ||
|
||
/** | ||
* @typedef AnswerHit | ||
* @type {object} | ||
* @property {Answer} _answer the object describing why the hit was chosen | ||
*/ | ||
|
||
/** | ||
* @typedef AnswersResult | ||
* @type {object} | ||
* @property {AnswerHit[]} hits the answer hits | ||
*/ | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. these docs aren't used as explanation while there's the definition file (only locally), so I don't think it's needed. Are you allowed to omit the return type all together or does eslint not allow it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What do you think? 5aa1206 |
||
/** | ||
* Start the search for answers with the parameters set in the state. | ||
* This method returns a promise. | ||
* @param {Object} options - the options for answers API call | ||
* @param {string[]} options.attributesForPrediction - Attributes to use for predictions. If empty, `searchableAttributes` is used instead. | ||
* @param {string[]} options.queryLanguages - The languages in the query. Currently only supports ['en']. | ||
* @param {number} options.nbHits - Maximum number of answers to retrieve from the Answers Engine. Cannot be greater than 1000. | ||
* | ||
* @return {AlgoliaSearchHelper} | ||
eunjae-lee marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* @return {promise.<AnswersResult>} the answer results | ||
*/ | ||
AlgoliaSearchHelper.prototype.findAnswers = function(options) { | ||
var state = this.state; | ||
var derivedHelper = this.derivedHelpers[0]; | ||
if (!derivedHelper) { | ||
return Promise.resolve([]); | ||
} | ||
var derivedState = derivedHelper.getModifiedState(state); | ||
var data = merge( | ||
{ | ||
attributesForPrediction: options.attributesForPrediction, | ||
nbHits: options.nbHits | ||
}, | ||
{ | ||
params: omit(requestBuilder._getHitsSearchParams(derivedState), [ | ||
'attributesToSnippet', | ||
'hitsPerPage', | ||
'restrictSearchableAttributes', | ||
'snippetEllipsisText' // FIXME remove this line once the engine is fixed. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unlike the doc, |
||
]) | ||
} | ||
); | ||
|
||
if ( | ||
typeof this.client.initIndex !== 'function' | ||
) { | ||
throw new Error( | ||
'search for answers was called, but this client does not have a function client.initIndex' | ||
); | ||
} | ||
var index = this.client.initIndex(derivedState.index); | ||
if (typeof index.findAnswers !== 'function') { | ||
throw new Error( | ||
'search for answers was called, but this client does not have a function client.initIndex(index).findAnswers' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is helpful, but the second error message gives pretty much the same information. Could it be consolidated to save space? How do we do it in searchForFacetValues? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unlike SFFV, the existence of |
||
); | ||
} | ||
return index.findAnswers(derivedState.query, options.queryLanguages, data); | ||
}; | ||
|
||
/** | ||
* Structure of each result when using | ||
* [`searchForFacetValues()`](reference.html#AlgoliaSearchHelper#searchForFacetValues) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
'use strict'; | ||
|
||
var algoliasearchHelper = require('../../../index'); | ||
|
||
function makeFakeFindAnswersResponse() { | ||
return { | ||
exhaustiveFacetsCount: true, | ||
facetHits: [], | ||
processingTimeMS: 3 | ||
}; | ||
} | ||
|
||
function setupTestEnvironment(helperOptions) { | ||
var findAnswers = jest.fn(function() { | ||
return Promise.resolve([makeFakeFindAnswersResponse()]); | ||
}); | ||
|
||
var fakeClient = { | ||
initIndex: function() { | ||
return { | ||
findAnswers: findAnswers | ||
}; | ||
} | ||
}; | ||
|
||
var helper = algoliasearchHelper(fakeClient, 'index', helperOptions); | ||
|
||
return { | ||
findAnswers: findAnswers, | ||
helper: helper | ||
}; | ||
} | ||
|
||
test('returns an empty array with no derived helper', function() { | ||
var env = setupTestEnvironment(); | ||
var helper = env.helper; | ||
var findAnswers = env.findAnswers; | ||
|
||
return helper | ||
.findAnswers({ | ||
attributesForPrediction: ['description'], | ||
queryLanguages: ['en'], | ||
nbHits: 1 | ||
}) | ||
.then(function(result) { | ||
expect(findAnswers).toHaveBeenCalledTimes(0); | ||
expect(result).toEqual([]); | ||
}); | ||
}); | ||
|
||
test('returns a correct result with one derivation', function() { | ||
var env = setupTestEnvironment(); | ||
var helper = env.helper; | ||
var findAnswers = env.findAnswers; | ||
|
||
helper.derive(function(state) { | ||
return state; | ||
}); | ||
|
||
return helper | ||
.findAnswers({ | ||
attributesForPrediction: ['description'], | ||
queryLanguages: ['en'], | ||
nbHits: 1 | ||
}) | ||
.then(function(result) { | ||
expect(findAnswers).toHaveBeenCalledTimes(1); | ||
expect(result).toEqual([makeFakeFindAnswersResponse()]); | ||
}); | ||
}); | ||
|
||
test('runs findAnswers with facets', function() { | ||
var env = setupTestEnvironment({facets: ['facet1']}); | ||
var helper = env.helper; | ||
var findAnswers = env.findAnswers; | ||
helper.addFacetRefinement('facet1', 'facetValue'); | ||
|
||
helper.derive(function(state) { | ||
return state; | ||
}); | ||
|
||
helper.setQuery('hello'); | ||
|
||
return helper | ||
.findAnswers({ | ||
attributesForPrediction: ['description'], | ||
queryLanguages: ['en'], | ||
nbHits: 1 | ||
}) | ||
.then(function() { | ||
expect(findAnswers).toHaveBeenCalledTimes(1); | ||
expect(findAnswers).toHaveBeenCalledWith('hello', ['en'], { | ||
attributesForPrediction: ['description'], | ||
nbHits: 1, | ||
params: { | ||
facetFilters: ['facet1:facetValue'], | ||
facets: ['facet1'], | ||
query: 'hello', | ||
tagFilters: '' | ||
} | ||
}); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you not use the return type of findAnswers on the client?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this method likely should be generic, like the client one
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've updated the dependency and now it's using the type from the client:
da8af13