我有大量要搜索的对象。
该数组包含> 60.000个项目,并且搜索性能有时会非常缓慢。
该数组中的一个对象如下所示:
{
"title": "title"
"company": "abc company"
"rating": 13 // internal rating based on comments and interaction
...
}
我要搜索标题和公司信息,然后按商品的等级进行排序。
这是我目前的搜索结果:
onSearchInput(searchTerm) {
(<any>window).clearTimeout(this.searchInputTimeout);
this.searchInputTimeout = window.setTimeout(() => {
this.searchForFood(searchTerm);
}, 500);
}
searchForFood(searchTerm) {
if (searchTerm.length > 1) {
this.searchResults = [];
this.foodList.map(item => {
searchTerm.split(' ').map(searchTermPart => {
if (item.title.toLowerCase().includes(searchTermPart.toLowerCase())
|| item.company.toLowerCase().includes(searchTermPart.toLowerCase())) {
this.searchResults.push(item);
}
});
});
this.searchResults = this.searchResults.sort(function(a, b) {
return a.rating - b.rating;
}).reverse();
} else {
this.searchResults = [];
}
}
问题:有什么方法可以改善搜索逻辑和性能?
答案 0 :(得分:2)
一堆提示:
setImmediate()
执行搜索的下一部分,这样用户的浏览器就不会在处理期间完全冻结。map()
就像您正在使用它一样,因为您不使用返回值,这很奇怪。最好使用forEach()
。更好的是,使用filter()
获取匹配的项目。some()
(如注释中指出的那样),因为这是提前返回的机会。sort()
对原始数组进行了变异,因此您无需重新分配它。sort()
的reverse()
通常是一种气味。相反,将条件的两边换成b - a
。includes()
,indexOf()
,roll-your-own-for
-循环,match()
(确保速度会变慢)答案 1 :(得分:0)
Alex的建议很好。我唯一的建议是,如果您有能力在空闲时间进行数据预处理(最好不要先进行渲染或交互),则可以将数据处理为修改的前缀特里。这样一来,您可以在O(k)时间中搜索项目,其中k是搜索项的长度(现在,您正在O(kn)时间中进行搜索,因为您查看了每个项目,然后执行includes
花费k时间(实际上由于toLowerCase
而变差,但我不想涉足其中)。
如果您不熟悉Trie是什么,希望下面的代码可以为您提供帮助,或者您可以使用所选的搜索引擎搜索信息。它基本上是嵌套哈希图中字符串中字符的映射。
下面是一些有关如何构造特里的示例代码:
function makeTries(data){
let companyTrie = {};
let titleTrie = {};
data.forEach(item => {
addToTrie(companyTrie, item.company, item, 0);
addToTrie(titleTrie, item.title, item, 0);
});
return {
companyTrie,
titleTrie
}
}
function addToTrie(trie, str, item, i){
trie.data = trie.data || [];
trie.data.push(item);
if(i >= str.length)
return;
if(! trie[str[i]]){
trie[str[i]] = {};
}
addToTrie(trie[str[i]], str, item, ++i);
}
function searchTrie(trie, term){
if(trie == undefined)
return [];
if(term == "")
return trie.data;
return searchTrie(trie[term[0]], term.substring(1));
}
var testData = [
{
company: "abc",
title: "def",
rank: 5
},{
company: "abd",
title: "deg",
rank: 5
},{
company: "afg",
title: "efg",
rank: 5
},{
company: "afgh",
title: "efh",
rank: 5
},
];
const tries = makeTries(testData);
console.log(searchTrie(tries.companyTrie, "afg"));