[Search] Updated search service interface

The search service's interface now just consists
of the two functions query() and isLoading().
query() returns a promise for an array or results,
which eliminates the need for timeout polling like
was previously done. The search providers
have also been changed to reutrn promises.
This commit is contained in:
slhale 2015-07-29 15:07:13 -07:00
parent 5ee8dd239b
commit 1619f236cf
5 changed files with 108 additions and 26 deletions

View File

@ -32,7 +32,7 @@
"provides": "searchService", "provides": "searchService",
"type": "provider", "type": "provider",
"implementation": "providers/GenericSearchProvider.js", "implementation": "providers/GenericSearchProvider.js",
"depends": [ "objectService", "workerService", "roots[]" ] "depends": [ "$q", "objectService", "workerService", "roots[]" ]
}, },
{ {
"provides": "searchService", "provides": "searchService",
@ -44,7 +44,7 @@
"provides": "searchService", "provides": "searchService",
"type": "aggregator", "type": "aggregator",
"implementation": "SearchAggregator.js", "implementation": "SearchAggregator.js",
"depends": [ "$timeout" ] "depends": [ "$q" ]
} }
], ],
"workers": [ "workers": [

View File

@ -37,17 +37,27 @@ define(
* to be treated as one. * to be treated as one.
* *
* @constructor * @constructor
* @param $q
* @param $timeout Angular's $timeout service, a replacement for * @param $timeout Angular's $timeout service, a replacement for
* JavaScript's setTimeout function. * JavaScript's setTimeout function.
* @param {SearchProvider[]} providers the search providers to be * @param {SearchProvider[]} providers the search providers to be
* aggregated * aggregated
*/ */
function SearchAggregator($timeout, providers) { function SearchAggregator($q,/* $timeout, */providers) {
var latestMergedResults = [], var //latestMergedResults = [],
lastMergeTimestamps = [], //lastMergeTimestamps = [],
lastQueryTimestamp = 0, //lastQueryTimestamp = 0,
loading; loading;
function concatArrays(arrays) {
var i,
array = [];
for (i = 0; i < arrays.length; i += 1) {
array = array.concat(arrays[i]);
}
return array;
}
// Remove duplicate objects that have the same ID // Remove duplicate objects that have the same ID
function filterRepeats(results) { function filterRepeats(results) {
var ids = [], var ids = [],
@ -112,6 +122,7 @@ define(
return results; return results;
} }
/*
// For documentation, see updateResults below. // For documentation, see updateResults below.
function updateResults() { function updateResults() {
var newerResults = [], var newerResults = [],
@ -132,7 +143,9 @@ define(
latestMergedResults = newerResults; latestMergedResults = newerResults;
lastMergeTimestamps = providerTimestamps; lastMergeTimestamps = providerTimestamps;
} }
*/
/*
// For documentation, see refresh below. // For documentation, see refresh below.
function refresh(callback) { function refresh(callback) {
// We are loading results // We are loading results
@ -158,20 +171,25 @@ define(
} }
waitForLatest(); waitForLatest();
} }
*/
// For documentation, see sendQuery below. // For documentation, see sendQuery below.
function queryAll(inputText, callback, timestamp) { function queryAll(inputText, callback, timestamp) {
var date, var i,
i; resultPromises = [];
// We are loading
loading = true;
// If there's not a timestamp, make this time the timestamp // If there's not a timestamp, make this time the timestamp
if (!timestamp) { if (!timestamp) {
date = new Date(); timestamp = Date.now();
timestamp = date.getTime();
} }
// Update globals // Update globals
lastQueryTimestamp = timestamp; //lastQueryTimestamp = timestamp;
/*
// Send the query to all the providers // Send the query to all the providers
for (i = 0; i < providers.length; i += 1) { for (i = 0; i < providers.length; i += 1) {
@ -183,6 +201,31 @@ define(
// Start refresh loop // Start refresh loop
refresh(callback); refresh(callback);
*/
// Instead, get back a bunch of promises from the providers
// Send the query to all the providers
for (i = 0; i < providers.length; i += 1) {
resultPromises.push(providers[i].query(inputText, timestamp, DEFAULT_MAX_RESULTS, DEFUALT_TIMEOUT));
}
//console.log('aggregator - result promises array', resultPromises);
return $q.all(resultPromises).then(function (resultsArrays) {
var results = concatArrays(resultsArrays);
results = filterRepeats(results);
results = orderByScore(results);
// TODO: sync this with stuff,, timestamps
//latestMergedResults = results;
//console.log('aggregator - final results', results);
// We are done loading
loading = false;
return results;
});
} }
return { return {
@ -198,7 +241,7 @@ define(
* latest results list, which allows us to see if it has been * latest results list, which allows us to see if it has been
* updated. If not provided, this aggregator will. * updated. If not provided, this aggregator will.
*/ */
sendQuery: queryAll, query: queryAll,
/** /**
* Repeatedly updates the latest results until those results are * Repeatedly updates the latest results until those results are
@ -207,7 +250,9 @@ define(
* @param callback A callback funtion which is a setter for the * @param callback A callback funtion which is a setter for the
* results list, originally passed by the user of this service. * results list, originally passed by the user of this service.
*/ */
/*
refresh: refresh, refresh: refresh,
*/
/** /**
* Get the latest search results that have been calculated. The * Get the latest search results that have been calculated. The
@ -219,17 +264,21 @@ define(
* @param stop (optional) The index of latestMergedResults at * @param stop (optional) The index of latestMergedResults at
* which to stop getting results. * which to stop getting results.
*/ */
/*
getLatestResults: function (start, stop) { getLatestResults: function (start, stop) {
return latestMergedResults.slice(start, stop); return latestMergedResults.slice(start, stop);
}, },
*/
/** /**
* Get the number of search results that have been calculated most * Get the number of search results that have been calculated most
* recently. * recently.
*/ */
/*
getNumResults: function () { getNumResults: function () {
return latestMergedResults.length; return latestMergedResults.length;
}, },
*/
/** /**
* Checks to see if we are still waiting for the results to be * Checks to see if we are still waiting for the results to be

View File

@ -32,13 +32,16 @@ define(function () {
function SearchController($scope, searchService) { function SearchController($scope, searchService) {
// Starting amount of results to load. Will get increased. // Starting amount of results to load. Will get increased.
var numResults = INITIAL_LOAD_NUMBER; var numResults = INITIAL_LOAD_NUMBER,
fullResults = [];
/*
// Function to be passed to the search service which allows it to set the // Function to be passed to the search service which allows it to set the
// search template's results list // search template's results list
function setControllerResults(results) { function setControllerResults(results) {
$scope.results = results.slice(0, numResults); $scope.results = results.slice(0, numResults);
} }
*/
function search() { function search() {
var inputText = $scope.ngModel.input; var inputText = $scope.ngModel.input;
@ -54,7 +57,12 @@ define(function () {
numResults = INITIAL_LOAD_NUMBER; numResults = INITIAL_LOAD_NUMBER;
// Send the query // Send the query
searchService.sendQuery(inputText, setControllerResults); //searchService.sendQuery(inputText, setControllerResults);
searchService.query(inputText).then(function (results) {
//console.log('controller - results', results);
fullResults = results;
$scope.results = results.slice(0, numResults);
});
} }
return { return {
@ -87,7 +95,7 @@ define(function () {
* Checks to see if there are more search results to display. * Checks to see if there are more search results to display.
*/ */
areMore: function () { areMore: function () {
return numResults < searchService.getNumResults(); return numResults < fullResults.length;//searchService.getNumResults();
}, },
/** /**
@ -96,7 +104,8 @@ define(function () {
*/ */
loadMore: function () { loadMore: function () {
numResults += LOAD_INCREMENT; numResults += LOAD_INCREMENT;
searchService.refresh(setControllerResults); $scope.results = fullResults.slice(0, numResults);
//searchService.refresh(setControllerResults);
} }
}; };
} }

View File

@ -108,13 +108,15 @@ define(
// Processes results from the format that elasticsearch returns to // Processes results from the format that elasticsearch returns to
// a list of search result objects (that contain domain objects) // a list of search result objects (that contain domain objects)
function processResults(rawResults, timestamp) { function processResults(rawResults, timestamp) {
var results = rawResults.hits.hits, var results = rawResults.data.hits.hits,
resultsLength = results.length, resultsLength = results.length,
ids = [], ids = [],
scores = {}, scores = {},
searchResults = [], searchResults = [],
i; i;
//console.log('es provider - raw results', rawResults);
/* /*
if (rawResults.data.hits.total > resultsLength) { if (rawResults.data.hits.total > resultsLength) {
// TODO: Somehow communicate this to the user // TODO: Somehow communicate this to the user
@ -133,11 +135,15 @@ define(
scores[ids[i]] = results[i][SCORE]; scores[ids[i]] = results[i][SCORE];
} }
//console.log('es provider - ids', ids);
// Get the domain objects from their IDs // Get the domain objects from their IDs
return objectService.getObjects(ids).then(function (objects) { return objectService.getObjects(ids).then(function (objects) {
var j, var j,
id; id;
//console.log('es provider - objects', objects);
for (j = 0; j < resultsLength; j += 1) { for (j = 0; j < resultsLength; j += 1) {
id = ids[j]; id = ids[j];
@ -154,6 +160,9 @@ define(
latestResults = searchResults; latestResults = searchResults;
lastSearchTimestamp = timestamp; lastSearchTimestamp = timestamp;
//console.log('es provider - search results', searchResults);
return searchResults; return searchResults;
}); });
} }
@ -185,11 +194,12 @@ define(
return $http({ return $http({
method: "GET", method: "GET",
url: esQuery url: esQuery
}).success(function (data, status) { }).then(function (rawResults) {
// ...then process the data // ...then process the data
return processResults(data, timestamp); return processResults(rawResults, timestamp);
}); });
} else { } else {
//console.log('es provider - empty search input');
latestResults = []; latestResults = [];
lastSearchTimestamp = timestamp; lastSearchTimestamp = timestamp;
return latestResults; return latestResults;

View File

@ -38,17 +38,21 @@ define(
* the filetree without using external search implementations. * the filetree without using external search implementations.
* *
* @constructor * @constructor
* @param $q
* @param {ObjectService} objectService the service from which * @param {ObjectService} objectService the service from which
* domain objects can be gotten. * domain objects can be gotten.
* @param {WorkerService} workerService the service which allows * @param {WorkerService} workerService the service which allows
* more easy creation of web workers. * more easy creation of web workers.
* @param {roots[]} roots an array of all the root domain objects. * @param {roots[]} roots an array of all the root domain objects.
*/ */
function GenericSearchProvider(objectService, workerService, roots) { function GenericSearchProvider($q, objectService, workerService, roots) {
var worker = workerService.run('genericSearchWorker'), var worker = workerService.run('genericSearchWorker'),
latestResults = [], latestResults = [],
lastSearchTimestamp = 0; lastSearchTimestamp = 0,
pendingQueries = {};
// pendingQueries is a dictionary with the key value pairs st
// the key is the timestamp and the value is the promise
// Tell the web worker to add a domain object's model to its list of items. // Tell the web worker to add a domain object's model to its list of items.
function indexItem(domainObject) { function indexItem(domainObject) {
var message; var message;
@ -103,6 +107,11 @@ define(
} }
// Update the timestamp to the one that this search was made with // Update the timestamp to the one that this search was made with
lastSearchTimestamp = event.data.timestamp; lastSearchTimestamp = event.data.timestamp;
//console.log('provider - about to resolve', latestResults);
// Resove the promise corresponding to this
pendingQueries[lastSearchTimestamp].resolve(latestResults);
}); });
} }
} }
@ -153,11 +162,14 @@ define(
}); });
} }
// For documentation, see query below. // For documentation, see query below.
function queryGeneric(input, timestamp, maxResults, timeout) { function query(input, timestamp, maxResults/*, timeout*/) {
var terms = [], var terms = [],
searchResults = [], searchResults = [],
resultsLength; defer = $q.defer();
pendingQueries[timestamp] = defer;
// Check to see if the user provided a maximum // Check to see if the user provided a maximum
// number of results to display // number of results to display
@ -169,13 +181,15 @@ define(
// Instead, assume that the items have already been indexed, and // Instead, assume that the items have already been indexed, and
// just send the query to the worker. // just send the query to the worker.
workerSearch(input, maxResults, timestamp); workerSearch(input, maxResults, timestamp);
return defer.promise;
} }
// Index the tree's contents once at the beginning // Index the tree's contents once at the beginning
getItems(); getItems();
// TODO: Is this a good assumption that the tree's contents will not // TODO: Is this a good assumption that the tree's contents will not
// change often enough? // change often enough?
// TODO: This makes the timeout parameter that queryGeneric takes // TODO: This makes the timeout parameter that query takes
// useless. See if timing out worker is an idea that works. // useless. See if timing out worker is an idea that works.
@ -202,7 +216,7 @@ define(
* @param timeout (optional) the time after which the search should * @param timeout (optional) the time after which the search should
* stop calculations and return partial results * stop calculations and return partial results
*/ */
query: queryGeneric, query: query,
/** /**
* Get the latest search results that have been calculated. The * Get the latest search results that have been calculated. The