diff --git a/platform/features/search/bundle.json b/platform/features/search/bundle.json index dd1ed78bab..46e06faad9 100644 --- a/platform/features/search/bundle.json +++ b/platform/features/search/bundle.json @@ -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": [ diff --git a/platform/features/search/src/SearchAggregator.js b/platform/features/search/src/SearchAggregator.js index 47cf1b037a..edea883cb1 100644 --- a/platform/features/search/src/SearchAggregator.js +++ b/platform/features/search/src/SearchAggregator.js @@ -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 diff --git a/platform/features/search/src/controllers/SearchController.js b/platform/features/search/src/controllers/SearchController.js index f4e2ec8070..ec7d533b73 100644 --- a/platform/features/search/src/controllers/SearchController.js +++ b/platform/features/search/src/controllers/SearchController.js @@ -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); } }; } diff --git a/platform/features/search/src/providers/ElasticsearchSearchProvider.js b/platform/features/search/src/providers/ElasticsearchSearchProvider.js index 4fcee9fca5..2e754a7898 100644 --- a/platform/features/search/src/providers/ElasticsearchSearchProvider.js +++ b/platform/features/search/src/providers/ElasticsearchSearchProvider.js @@ -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; diff --git a/platform/features/search/src/providers/GenericSearchProvider.js b/platform/features/search/src/providers/GenericSearchProvider.js index 0ebff917f5..3e3abc7889 100644 --- a/platform/features/search/src/providers/GenericSearchProvider.js +++ b/platform/features/search/src/providers/GenericSearchProvider.js @@ -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