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

View File

@ -37,17 +37,27 @@ define(
* to be treated as one.
*
* @constructor
* @param $q
* @param $timeout Angular's $timeout service, a replacement for
* JavaScript's setTimeout function.
* @param {SearchProvider[]} providers the search providers to be
* aggregated
*/
function SearchAggregator($timeout, providers) {
var latestMergedResults = [],
lastMergeTimestamps = [],
lastQueryTimestamp = 0,
function SearchAggregator($q,/* $timeout, */providers) {
var //latestMergedResults = [],
//lastMergeTimestamps = [],
//lastQueryTimestamp = 0,
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
function filterRepeats(results) {
var ids = [],
@ -112,6 +122,7 @@ define(
return results;
}
/*
// For documentation, see updateResults below.
function updateResults() {
var newerResults = [],
@ -132,7 +143,9 @@ define(
latestMergedResults = newerResults;
lastMergeTimestamps = providerTimestamps;
}
*/
/*
// For documentation, see refresh below.
function refresh(callback) {
// We are loading results
@ -158,20 +171,25 @@ define(
}
waitForLatest();
}
*/
// For documentation, see sendQuery below.
function queryAll(inputText, callback, timestamp) {
var date,
i;
var i,
resultPromises = [];
// We are loading
loading = true;
// If there's not a timestamp, make this time the timestamp
if (!timestamp) {
date = new Date();
timestamp = date.getTime();
timestamp = Date.now();
}
// Update globals
lastQueryTimestamp = timestamp;
//lastQueryTimestamp = timestamp;
/*
// Send the query to all the providers
for (i = 0; i < providers.length; i += 1) {
@ -183,6 +201,31 @@ define(
// Start refresh loop
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 {
@ -198,7 +241,7 @@ define(
* latest results list, which allows us to see if it has been
* updated. If not provided, this aggregator will.
*/
sendQuery: queryAll,
query: queryAll,
/**
* 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
* results list, originally passed by the user of this service.
*/
/*
refresh: refresh,
*/
/**
* Get the latest search results that have been calculated. The
@ -219,17 +264,21 @@ define(
* @param stop (optional) The index of latestMergedResults at
* which to stop getting results.
*/
/*
getLatestResults: function (start, stop) {
return latestMergedResults.slice(start, stop);
},
*/
/**
* Get the number of search results that have been calculated most
* recently.
*/
/*
getNumResults: function () {
return latestMergedResults.length;
},
*/
/**
* 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) {
// 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
// search template's results list
function setControllerResults(results) {
$scope.results = results.slice(0, numResults);
}
*/
function search() {
var inputText = $scope.ngModel.input;
@ -54,7 +57,12 @@ define(function () {
numResults = INITIAL_LOAD_NUMBER;
// 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 {
@ -87,7 +95,7 @@ define(function () {
* Checks to see if there are more search results to display.
*/
areMore: function () {
return numResults < searchService.getNumResults();
return numResults < fullResults.length;//searchService.getNumResults();
},
/**
@ -96,7 +104,8 @@ define(function () {
*/
loadMore: function () {
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
// a list of search result objects (that contain domain objects)
function processResults(rawResults, timestamp) {
var results = rawResults.hits.hits,
var results = rawResults.data.hits.hits,
resultsLength = results.length,
ids = [],
scores = {},
searchResults = [],
i;
//console.log('es provider - raw results', rawResults);
/*
if (rawResults.data.hits.total > resultsLength) {
// TODO: Somehow communicate this to the user
@ -133,11 +135,15 @@ define(
scores[ids[i]] = results[i][SCORE];
}
//console.log('es provider - ids', ids);
// Get the domain objects from their IDs
return objectService.getObjects(ids).then(function (objects) {
var j,
id;
//console.log('es provider - objects', objects);
for (j = 0; j < resultsLength; j += 1) {
id = ids[j];
@ -154,6 +160,9 @@ define(
latestResults = searchResults;
lastSearchTimestamp = timestamp;
//console.log('es provider - search results', searchResults);
return searchResults;
});
}
@ -185,11 +194,12 @@ define(
return $http({
method: "GET",
url: esQuery
}).success(function (data, status) {
}).then(function (rawResults) {
// ...then process the data
return processResults(data, timestamp);
return processResults(rawResults, timestamp);
});
} else {
//console.log('es provider - empty search input');
latestResults = [];
lastSearchTimestamp = timestamp;
return latestResults;

View File

@ -38,17 +38,21 @@ define(
* the filetree without using external search implementations.
*
* @constructor
* @param $q
* @param {ObjectService} objectService the service from which
* domain objects can be gotten.
* @param {WorkerService} workerService the service which allows
* more easy creation of web workers.
* @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'),
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.
function indexItem(domainObject) {
var message;
@ -103,6 +107,11 @@ define(
}
// Update the timestamp to the one that this search was made with
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.
function queryGeneric(input, timestamp, maxResults, timeout) {
function query(input, timestamp, maxResults/*, timeout*/) {
var terms = [],
searchResults = [],
resultsLength;
defer = $q.defer();
pendingQueries[timestamp] = defer;
// Check to see if the user provided a maximum
// number of results to display
@ -169,13 +181,15 @@ define(
// Instead, assume that the items have already been indexed, and
// just send the query to the worker.
workerSearch(input, maxResults, timestamp);
return defer.promise;
}
// Index the tree's contents once at the beginning
getItems();
// TODO: Is this a good assumption that the tree's contents will not
// 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.
@ -202,7 +216,7 @@ define(
* @param timeout (optional) the time after which the search should
* stop calculations and return partial results
*/
query: queryGeneric,
query: query,
/**
* Get the latest search results that have been calculated. The