mirror of
https://github.com/nasa/openmct.git
synced 2025-06-01 23:20:50 +00:00
[Search] Basic aggregator works
The search view now behaves as it previously did. The search aggregator is set to just use ElasticSearch, but it works.
This commit is contained in:
parent
6f2ad0dadc
commit
cd3c2312a5
@ -37,11 +37,24 @@
|
|||||||
"uses": [ "composition" ]
|
"uses": [ "composition" ]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"services": [
|
"components": [
|
||||||
{
|
{
|
||||||
"key": "searchService",
|
"provides": "searchService",
|
||||||
"implementation": "SearchService.js",
|
"type": "provider",
|
||||||
|
"implementation": "providers/ElasticsearchSearchProvider.js",
|
||||||
"depends": [ "$http", "objectService", "ELASTIC_ROOT" ]
|
"depends": [ "$http", "objectService", "ELASTIC_ROOT" ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"provides": "searchService",
|
||||||
|
"type": "provider",
|
||||||
|
"implementation": "providers/EverythingSearchProvider.js",
|
||||||
|
"depends": [ "objectService" ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"provides": "searchService",
|
||||||
|
"type": "aggregator",
|
||||||
|
"implementation": "SearchAggregator.js",
|
||||||
|
"depends": [ "$q" ]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
/*global define*/
|
/*global define*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module defining ModelAggregator. Created by vwoeltje on 11/7/14.
|
* Module defining SearchAggregator. Created by shale on 07/16/2015.
|
||||||
*/
|
*/
|
||||||
define(
|
define(
|
||||||
[],
|
[],
|
||||||
@ -30,15 +30,19 @@ define(
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows multiple services which provide models for domain objects
|
* Allows multiple services which provide search functionality
|
||||||
* to be treated as one.
|
* to be treated as one.
|
||||||
*
|
*
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param {ModelProvider[]} providers the model providers to be
|
* @param {SearchProvider[]} providers the search providers to be
|
||||||
* aggregated
|
* aggregated
|
||||||
*/
|
*/
|
||||||
function ModelAggregator($q, providers) {
|
function SearchAggregator($q, providers) {
|
||||||
|
return {
|
||||||
|
query: providers[0].query
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
// Pick a domain object model to use, favoring the one
|
// Pick a domain object model to use, favoring the one
|
||||||
// with the most recent timestamp
|
// with the most recent timestamp
|
||||||
function pick(a, b) {
|
function pick(a, b) {
|
||||||
@ -78,6 +82,7 @@ define(
|
|||||||
* where keys are object identifiers and values
|
* where keys are object identifiers and values
|
||||||
* are object models.
|
* are object models.
|
||||||
*/
|
*/
|
||||||
|
/*
|
||||||
getModels: function (ids) {
|
getModels: function (ids) {
|
||||||
return $q.all(providers.map(function (provider) {
|
return $q.all(providers.map(function (provider) {
|
||||||
return provider.getModels(ids);
|
return provider.getModels(ids);
|
||||||
@ -86,8 +91,9 @@ define(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
return ModelAggregator;
|
return SearchAggregator;
|
||||||
}
|
}
|
||||||
);
|
);
|
@ -0,0 +1,191 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
/*global define*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module defining ElasticsearchSearchProvider. Created by shale on 07/16/2015.
|
||||||
|
*/
|
||||||
|
define(
|
||||||
|
[],
|
||||||
|
function () {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// JSLint doesn't like underscore-prefixed properties,
|
||||||
|
// so hide them here.
|
||||||
|
var ID = "_id",
|
||||||
|
SCORE = "_score",
|
||||||
|
DEFAULT_MAX_RESULTS = 100;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A model service which reads domain object models from an external
|
||||||
|
* persistence service.
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
* @param {PersistenceService} persistenceService the service in which
|
||||||
|
* domain object models are persisted.
|
||||||
|
* @param $q Angular's $q service, for working with promises
|
||||||
|
* @param {string} SPACE the name of the persistence space from which
|
||||||
|
* models should be retrieved.
|
||||||
|
*/
|
||||||
|
function ElasticsearchSearchProvider($http, objectService, ROOT) {
|
||||||
|
|
||||||
|
// Check to see if the input has any special options
|
||||||
|
function isDefaultFormat(searchTerm) {
|
||||||
|
// If the input has a property option, not default
|
||||||
|
if (searchTerm.includes('name:') || searchTerm.includes('type:')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the fuzziness operator to the search term
|
||||||
|
function addFuzziness(searchTerm, editDistance) {
|
||||||
|
if (!editDistance) {
|
||||||
|
editDistance = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return searchTerm.split(' ').map(function (s) {
|
||||||
|
if (s.includes('"')) {
|
||||||
|
console.log('true');
|
||||||
|
return s;
|
||||||
|
} else {
|
||||||
|
return s + '~' + editDistance;
|
||||||
|
}
|
||||||
|
}).join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Currently specific to elasticsearch
|
||||||
|
function processSearchTerm(searchTerm) {
|
||||||
|
// Shave any spaces off of the ends of the input
|
||||||
|
while (searchTerm.substr(0, 1) === ' ') {
|
||||||
|
searchTerm = searchTerm.substring(1, searchTerm.length);
|
||||||
|
}
|
||||||
|
while (searchTerm.substr(searchTerm.length - 1, 1) === ' ') {
|
||||||
|
searchTerm = searchTerm.substring(0, searchTerm.length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDefaultFormat(searchTerm)) {
|
||||||
|
// Add fuzziness for completeness
|
||||||
|
searchTerm = addFuzziness(searchTerm);
|
||||||
|
|
||||||
|
// Searching 'name' by default
|
||||||
|
searchTerm = 'name:' + searchTerm;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('search term ', searchTerm);
|
||||||
|
return searchTerm;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Processes results from the format that elasticsearch returns to
|
||||||
|
// a list of objects in the format that mct-representation can use
|
||||||
|
function processResults(rawResults) {
|
||||||
|
var results = rawResults.data.hits.hits,
|
||||||
|
resultsLength = results.length,
|
||||||
|
ids = [],
|
||||||
|
i;
|
||||||
|
|
||||||
|
if (rawResults.data.hits.total > resultsLength) {
|
||||||
|
// TODO: Somehow communicate this to the user
|
||||||
|
console.log('Total number of results greater than displayed results');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the result objects' IDs
|
||||||
|
for (i = 0; i < resultsLength; i += 1) {
|
||||||
|
ids.push(results[i][ID]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the domain objects from their IDs
|
||||||
|
return objectService.getObjects(ids).then(function (objects) {
|
||||||
|
var output = [],
|
||||||
|
id,
|
||||||
|
j;
|
||||||
|
|
||||||
|
for (j = 0; j < resultsLength; j += 1) {
|
||||||
|
id = ids[j];
|
||||||
|
|
||||||
|
// Include any item except folders
|
||||||
|
if (objects[id].getModel) {
|
||||||
|
if (objects[id].getModel().type !== "folder") {
|
||||||
|
output.push(objects[id]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches through the filetree for domain objects using a search
|
||||||
|
* term. This is done through querying elasticsearch.
|
||||||
|
* Notes:
|
||||||
|
* * The order of the results is from highest to lowest score,
|
||||||
|
* as elsaticsearch determines them to be.
|
||||||
|
* * Folders are not included in the results.
|
||||||
|
* * Wildcards are supported.
|
||||||
|
* * Fuzziness is used to produce more results that are still
|
||||||
|
* relevant. (All results within a certain edit distance.)
|
||||||
|
* * More search details at
|
||||||
|
* https://www.elastic.co/guide/en/elasticsearch/reference/current/search-uri-request.html
|
||||||
|
*
|
||||||
|
* @param inputID the name of the ID property of the html text
|
||||||
|
* input where this funcion should find the search term
|
||||||
|
* @param maxResults (optional) the maximum number of results
|
||||||
|
* that this function should return
|
||||||
|
*/
|
||||||
|
function queryElasticsearch(inputID, maxResults) {
|
||||||
|
var searchTerm;
|
||||||
|
|
||||||
|
// Check to see if the user provided a maximum
|
||||||
|
// number of results to display
|
||||||
|
if (!maxResults) {
|
||||||
|
// Else, we provide a default value.
|
||||||
|
maxResults = DEFAULT_MAX_RESULTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the user input
|
||||||
|
searchTerm = document.getElementById(inputID).value;
|
||||||
|
|
||||||
|
// Process search term
|
||||||
|
searchTerm = processSearchTerm(searchTerm);
|
||||||
|
|
||||||
|
// Get the data...
|
||||||
|
return $http({
|
||||||
|
method: "GET",
|
||||||
|
url: ROOT + "/_search/?q=" + searchTerm +
|
||||||
|
"&size=" + maxResults
|
||||||
|
}).then(function (rawResults) {
|
||||||
|
// ...then process the data
|
||||||
|
return processResults(rawResults);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
query: queryElasticsearch
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return ElasticsearchSearchProvider;
|
||||||
|
}
|
||||||
|
);
|
@ -0,0 +1,147 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
/*global define*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module defining EverythingSearchProvider. Created by shale on 07/16/2015.
|
||||||
|
*/
|
||||||
|
define(
|
||||||
|
[],
|
||||||
|
function () {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A model service which reads domain object models from an external
|
||||||
|
* persistence service.
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
* @param {PersistenceService} persistenceService the service in which
|
||||||
|
* domain object models are persisted.
|
||||||
|
* @param $q Angular's $q service, for working with promises
|
||||||
|
* @param {string} SPACE the name of the persistence space from which
|
||||||
|
* models should be retrieved.
|
||||||
|
*/
|
||||||
|
function EverythingSearchProvider(objectService) {
|
||||||
|
|
||||||
|
// Recursive helper function for getItems()
|
||||||
|
function itemsHelper(children, i) {
|
||||||
|
if (i >= children.length) {
|
||||||
|
// Done!
|
||||||
|
return children;
|
||||||
|
} else if (children[i].hasCapability('composition')) {
|
||||||
|
// This child has children
|
||||||
|
return children[i].getCapability('composition').invoke().then(function (grandchildren) {
|
||||||
|
// Add grandchildren to the end of the list
|
||||||
|
// They will also be checked for composition
|
||||||
|
return itemsHelper(children.concat(grandchildren), i + 1);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// This child is a leaf
|
||||||
|
return itemsHelper(children, i + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts the filetree into a list
|
||||||
|
function getItems() {
|
||||||
|
// Aquire My Items (root folder)
|
||||||
|
return objectService.getObjects(['mine']).then(function (objects) {
|
||||||
|
// Get all of its descendents
|
||||||
|
return itemsHelper([objects.mine], 0).then(function (c) {
|
||||||
|
return c;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches through the filetree for domain objects which match
|
||||||
|
* the search term. This function is to be used as a fallback
|
||||||
|
* in the case where other search services are not avaliable.
|
||||||
|
* Notes:
|
||||||
|
* * The order of the results is not guarenteed.
|
||||||
|
* * A domain object qualifies as a match for a search term if
|
||||||
|
* the object's name property contains the exact search term
|
||||||
|
* as a substring.
|
||||||
|
* * Folders are not included in the results.
|
||||||
|
* * Wildcards are not supported.
|
||||||
|
*
|
||||||
|
* @param inputID the name of the ID property of the html text
|
||||||
|
* input where this funcion should find the search term
|
||||||
|
* @param maxResults (optional) the maximum number of results
|
||||||
|
* that this function should return
|
||||||
|
*/
|
||||||
|
function queryManual(inputID, maxResults) {
|
||||||
|
var term,
|
||||||
|
searchResults = [],
|
||||||
|
resultsLength,
|
||||||
|
itemModel,
|
||||||
|
itemName,
|
||||||
|
i;
|
||||||
|
|
||||||
|
// Check to see if the user provided a maximum
|
||||||
|
// number of results to display
|
||||||
|
if (!maxResults) {
|
||||||
|
// Else, we provide a default value.
|
||||||
|
maxResults = DEFAULT_MAX_RESULTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the user input
|
||||||
|
term = document.getElementById(inputID).value;
|
||||||
|
|
||||||
|
// Make not case sensitive
|
||||||
|
term = term.toLocaleLowerCase();
|
||||||
|
|
||||||
|
// Get items list
|
||||||
|
return getItems().then(function (items) {
|
||||||
|
// Keep track of the number of results to display
|
||||||
|
if (items.length < maxResults) {
|
||||||
|
resultsLength = items.length;
|
||||||
|
} else {
|
||||||
|
resultsLength = maxResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then filter through the items list
|
||||||
|
for (i = 0; i < resultsLength; i += 1) {
|
||||||
|
// Prevent errors from getModel not being defined
|
||||||
|
if (items[i].getModel) {
|
||||||
|
itemModel = items[i].getModel();
|
||||||
|
itemName = itemModel.name.toLocaleLowerCase();
|
||||||
|
|
||||||
|
// Include any matching items, except folders
|
||||||
|
if (itemName.includes(term) && itemModel.type !== "folder") {
|
||||||
|
searchResults.push(items[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return searchResults;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
query: queryManual
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return EverythingSearchProvider;
|
||||||
|
}
|
||||||
|
);
|
Loading…
x
Reference in New Issue
Block a user