我使用stty raw -echo
试图在JS对象中进行“多个单词”搜索,以获取包含所要查找的每个单词的记录。
我的数据结构如下(来自fuse.js):
Fuse.js
我的问题是我的设置适用于单字搜索(例如[{
title: "The Lost Symbol",
author: {
firstName: "Dan",
lastName: "Brown"
}
}, ...]
),而不适用于更多单词(Brown
或Dan Brown
)。
保险丝选项:
Dan Brown Vinci
{
shouldSort: true,
matchAllTokens: true,
findAllMatches: true,
includeScore: true,
threshold: 0,
location: 0,
distance: 100,
maxPatternLength: 32,
minMatchCharLength: 1,
keys: [
"title",
"author.firstName",
"author.lastName"
]
}
new Vue({
el: "#app",
data: {
Fuse: null,
searchText: '',
result : [],
fuseOptions: {
shouldSort: true,
matchAllTokens: true,
findAllMatches: true,
includeScore: true,
threshold: 0,
location: 0,
distance: 100,
maxPatternLength: 32,
minMatchCharLength: 1,
keys: [
"title",
"author.firstName",
"author.lastName"
]
},
list: [{
title: "Old Man's War",
author: {
firstName: "John",
lastName: "Scalzi"
}
},
{
title: "The Lock Artist",
author: {
firstName: "Steve",
lastName: "Hamilton"
}
},
{
title: "HTML5",
author: {
firstName: "Remy",
lastName: "Sharp"
}
},
{
title: "Right Ho Jeeves",
author: {
firstName: "P.D",
lastName: "Woodhouse"
}
},
{
title: "The Code of the Wooster",
author: {
firstName: "P.D",
lastName: "Woodhouse"
}
},
{
title: "Thank You Jeeves",
author: {
firstName: "P.D",
lastName: "Woodhouse"
}
},
{
title: "The DaVinci Code",
author: {
firstName: "Dan",
lastName: "Brown"
}
},
{
title: "Angels & Demons",
author: {
firstName: "Dan",
lastName: "Brown"
}
},
{
title: "The Silmarillion",
author: {
firstName: "J.R.R",
lastName: "Tolkien"
}
},
{
title: "Syrup",
author: {
firstName: "Max",
lastName: "Barry"
}
},
{
title: "The Lost Symbol",
author: {
firstName: "Dan",
lastName: "Brown"
}
},
{
title: "The Book of Lies",
author: {
firstName: "Brad",
lastName: "Meltzer"
}
},
{
title: "Lamb",
author: {
firstName: "Christopher",
lastName: "Moore"
}
},
{
title: "Fool",
author: {
firstName: "Christopher",
lastName: "Moore"
}
},
{
title: "Incompetence",
author: {
firstName: "Rob",
lastName: "Grant"
}
},
{
title: "Fat",
author: {
firstName: "Rob",
lastName: "Grant"
}
},
{
title: "Colony",
author: {
firstName: "Rob",
lastName: "Grant"
}
},
{
title: "Backwards, Red Dwarf",
author: {
firstName: "Rob",
lastName: "Grant"
}
},
{
title: "The Grand Design",
author: {
firstName: "Stephen",
lastName: "Hawking"
}
},
{
title: "The Book of Samson",
author: {
firstName: "David",
lastName: "Maine"
}
},
{
title: "The Preservationist",
author: {
firstName: "David",
lastName: "Maine"
}
},
{
title: "Fallen",
author: {
firstName: "David",
lastName: "Maine"
}
},
{
title: "Monster 1959",
author: {
firstName: "David",
lastName: "Maine"
}
}
]
},
methods: {
fuseSearch: function() {
let self = this;
this.result = this.Fuse.search(self.searchText)
}
},
mounted() {
let self = this
this.Fuse = new window.Fuse(self.list, self.fuseOptions);
}
})
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
table {
width: 100%;
margin-top:20px
}
table th{
font-weight:bold
}
table td{
padding-top:5px
}
input{
height:30px;
width:200px;
font-size:14px
}
答案 0 :(得分:3)
不幸的是,fuse.js 没有查看所有字段,而是一个匹配的字段。我通过将所有字段放入一个带有字符串数组的字段来解决这个问题。
示例:
[{
title: "The Lost Symbol",
author: {
firstName: "Dan",
lastName: "Brown"
},
keywords: ["The Lost Symbol", "Dan", "Brown"] //values of title, firstname & lastname
}, ...]
并且只需指定 keywords Fuse 选项的 keys 字段
{
shouldSort: true,
matchAllTokens: true,
findAllMatches: true,
includeScore: true,
threshold: 0,
location: 0,
distance: 100,
maxPatternLength: 32,
minMatchCharLength: 1,
keys: ["keywords"] //just put keywords alone
}
这对我有用。希望它也适用于您。
答案 1 :(得分:1)
我们也有类似的需求,最终解决如下:
(注意:我最初是在 https://github.com/krisk/Fuse/issues/235#issuecomment-850269634 上分享的)
对于通过谷歌搜索或其他方式最终到达这里的任何人,我们最终在 https://github.com/sparkletown/sparkle/pull/1460 中采用了不同的方法(感谢@yarikoptic > 出色的调试、探索和改进工作)
我们基本上使用正则表达式 (tokeniseStringWithQuotesBySpaces
) 拆分搜索查询,以标记每个单词,但将 "
和 "
之间的单词保留为单个标记):>
/**
* Split the provided string by spaces (ignoring spaces within "quoted text") into an array of tokens.
*
* @param string
*
* @see https://stackoverflow.com/a/16261693/1265472
*
* @debt Depending on the outcome of https://github.com/github/codeql/issues/5964 we may end up needing to change
* this regex for performance reasons.
*/
export const tokeniseStringWithQuotesBySpaces = (string: string): string[] =>
string.match(/("[^"]*?"|[^"\s]+)+(?=\s*|\s*$)/g) ?? [];
(注意:请检查 https://github.com/github/codeql/issues/5964,因为正则表达式可能存在 ReDoS 漏洞,但也可能只是 CodeQL 扫描程序中的误报)
使用我们的标准保险丝配置:
new Fuse(filteredPosterVenues, {
keys: [
"name",
"poster.title",
"poster.authorName",
"poster.categories",
],
threshold: 0.2, // 0.1 seems to be exact, default 0.6: brings too distant if anyhow related hits
ignoreLocation: true, // default False: True - to search ignoring location of the words.
findAllMatches: true,
}),
然后使用我们的 tokeniseStringWithQuotesBySpaces
tokeniser + 自定义 Fuse 查询(使用 $and
连接我们的每个标记,然后使用 $or
连接不同的字段)进行搜索:
const tokenisedSearchQuery = tokeniseStringWithQuotesBySpaces(
normalizedSearchQuery
);
if (tokenisedSearchQuery.length === 0) return filteredPosterVenues;
return fuseVenues
.search({
$and: tokenisedSearchQuery.map((searchToken: string) => {
const orFields: Fuse.Expression[] = [
{ name: searchToken },
{ "poster.title": searchToken },
{ "poster.authorName": searchToken },
{ "poster.categories": searchToken },
];
return {
$or: orFields,
};
}),
})
.map((fuseResult) => fuseResult.item);
从我今天的测试来看,这似乎非常有效地满足了我们的需求。>