Mongodb 部分匹配
Mongodb partial matching
如何以一个编辑距离获取 mongodb 中的所有文档。
我有 collection 足球队。
{
name: 'Real Madrir',
nicknames: ['Real', 'Madrid', 'Real Madrir' ... ]
}
并且用户搜索了 Real Madid
个 Maddrid
或其他。
我想 return 所有包含昵称的文档与给定搜索字符串的编辑距离为 0 或 1。
我认为有两种方法,mongodb全文搜索或正则表达式。
那么我可以写这样的正则表达式或查询吗?
谢谢。
对于全文搜索,首先您必须在 nicknames
字段上创建一个 Text Index。在创建索引之前插入的文档将不可搜索。搜索仅适用于 在 创建索引后插入的文档。然后,当您使用 MongoDb 的 $text
和 $search
运算符执行搜索时,MongoDb 将 return 其 nicknames
字段对应于搜索文本。对于正则表达式匹配,MongoDb 有一个可以使用的 $regex
运算符。
这里有几个简短的例子:
全文搜索
- 将此脚本另存为
football.js
。它将创建一个 teams
集合,其中包含一个文本索引和两个文档供我们搜索。
// create football database
var db = connect("localhost:27017/football");
/*
note:
You may also create indexes from your console
using the MongoDb shell. Actually each of these
statements may be run from the shell. I'm using
a script file for convenience.
*/
// create Text Index on the 'nicknames' field
// so full-text search works
db.teams.createIndex({"nicknames":"text"});
// insert two teams to search for
db.teams.insert({
name: 'Real Madrir',
nicknames: ['Real', 'Madrid', 'Real Madrir' ]
})
db.teams.insert({
name: 'Fake Madrir',
nicknames: ['Fake']
})
打开终端并导航到保存 football.js
的目录,然后通过键入 mongo football.js
针对本地 MongoDb 实例 运行 此脚本].
从您的终端输入 mongo
以打开 MongoDb Shell 并通过输入 use football
切换到 football
数据库。
进入足球数据库后,使用 db.teams.find({"$text":{"$search":"<search-text>"}})
搜索您的文档之一
> use football
// find Real Madrir
> db.teams.find({"$text":{"$search":"Real"}})
// find Fake Madrir
> db.teams.find({"$text":{"$search":"Fake"}})
正则表达式
如果您想使用正则表达式进行搜索,则无需创建索引。只需使用 mongodb 的 $regex
运算符进行搜索:
//find Real Madrir
db.teams.find({"nicknames": {"$regex": /Real/}})
db.teams.find({"nicknames": {"$regex": /Real Madrir/}})
//find Fake Madrir
db.teams.find({"nicknames": {"$regex": /Fa/}})
db.teams.find({"nicknames": {"$regex": /ke/}})
猫鼬
这就是每个搜索在 NodeJS 中的工作方式 mongoose:
var searchText = "Madrir"; // or some value from request.body
var searchRegex = new RegExp(searchText);
var fullTextSearchOptions = {
"$text":{
"$search": searchText
}
};
var regexSearchOptions = {
"nicknames": {
"$regex": searchRegex
}
};
// full-text search
Team.find(fullTextSearchOptions, function(err, teams){
if(err){
// ...
}else if(teams){
// ...
}
})
// regex search
Team.find(regexSearchOptions, function(err, teams){
if(err){
// ...
}else if(teams){
// ...
}
})
来晚了,但希望能帮助其他搜索此内容的人。
唯一的选择是不使用正则表达式(因此不使用索引,对于大型数据集会非常慢)或使用正常的 $text
搜索(快速索引搜索但不部分匹配)。还有第三个选项使用更多的索引内存,但都支持部分匹配并使用索引(所以速度很快)。
您可以通过从字符串字段生成字符串数组(例如 name
)并将生成的数组存储在索引数组字段中来创建自己的“索引”(我们称之为 _nameSearch
).像这样
const getSearchArray: (str) => string[] = _str => {
const str = _str.toLowerCase();
const output = [];
let acc = "";
let accTotal = "";
str.split("").forEach(char => {
// Reset accumulator when space is encountered
// Otherwise, add the new phrase to the array
accTotal += char;
output.push(accTotal);
if (char === " ") {
acc = "";
} else {
acc += char;
output.push(acc);
}
});
return Array.from(new Set(output));
};
因此,如果 name
值为“选项”,_nameSearch
将是 ["o", "op", "opt", "opti", "option"]
那么您可以索引 _nameSearch
。所以你的架构看起来像这样:
const schema = new Schema(
{
name: String,
_nameSearch: { type: [String], index: true },
...
}
);
查询 name
字段就像 db.collection.find({ _nameSearch: SEARCH_STRING })
一样简单。而且您将能够找到部分匹配项并且还可以使用索引(因此搜索速度非常快)。但是,您将为 name
字段使用更大一点的索引,因此这是一种权衡,但也是一个值得考虑的可行选择。
如何以一个编辑距离获取 mongodb 中的所有文档。
我有 collection 足球队。
{
name: 'Real Madrir',
nicknames: ['Real', 'Madrid', 'Real Madrir' ... ]
}
并且用户搜索了 Real Madid
个 Maddrid
或其他。
我想 return 所有包含昵称的文档与给定搜索字符串的编辑距离为 0 或 1。
我认为有两种方法,mongodb全文搜索或正则表达式。
那么我可以写这样的正则表达式或查询吗?
谢谢。
对于全文搜索,首先您必须在 nicknames
字段上创建一个 Text Index。在创建索引之前插入的文档将不可搜索。搜索仅适用于 在 创建索引后插入的文档。然后,当您使用 MongoDb 的 $text
和 $search
运算符执行搜索时,MongoDb 将 return 其 nicknames
字段对应于搜索文本。对于正则表达式匹配,MongoDb 有一个可以使用的 $regex
运算符。
这里有几个简短的例子:
全文搜索
- 将此脚本另存为
football.js
。它将创建一个teams
集合,其中包含一个文本索引和两个文档供我们搜索。
// create football database
var db = connect("localhost:27017/football");
/*
note:
You may also create indexes from your console
using the MongoDb shell. Actually each of these
statements may be run from the shell. I'm using
a script file for convenience.
*/
// create Text Index on the 'nicknames' field
// so full-text search works
db.teams.createIndex({"nicknames":"text"});
// insert two teams to search for
db.teams.insert({
name: 'Real Madrir',
nicknames: ['Real', 'Madrid', 'Real Madrir' ]
})
db.teams.insert({
name: 'Fake Madrir',
nicknames: ['Fake']
})
打开终端并导航到保存
football.js
的目录,然后通过键入mongo football.js
针对本地 MongoDb 实例 运行 此脚本].从您的终端输入
mongo
以打开 MongoDb Shell 并通过输入use football
切换到football
数据库。进入足球数据库后,使用
db.teams.find({"$text":{"$search":"<search-text>"}})
搜索您的文档之一
> use football
// find Real Madrir
> db.teams.find({"$text":{"$search":"Real"}})
// find Fake Madrir
> db.teams.find({"$text":{"$search":"Fake"}})
正则表达式
如果您想使用正则表达式进行搜索,则无需创建索引。只需使用 mongodb 的 $regex
运算符进行搜索:
//find Real Madrir
db.teams.find({"nicknames": {"$regex": /Real/}})
db.teams.find({"nicknames": {"$regex": /Real Madrir/}})
//find Fake Madrir
db.teams.find({"nicknames": {"$regex": /Fa/}})
db.teams.find({"nicknames": {"$regex": /ke/}})
猫鼬
这就是每个搜索在 NodeJS 中的工作方式 mongoose:
var searchText = "Madrir"; // or some value from request.body
var searchRegex = new RegExp(searchText);
var fullTextSearchOptions = {
"$text":{
"$search": searchText
}
};
var regexSearchOptions = {
"nicknames": {
"$regex": searchRegex
}
};
// full-text search
Team.find(fullTextSearchOptions, function(err, teams){
if(err){
// ...
}else if(teams){
// ...
}
})
// regex search
Team.find(regexSearchOptions, function(err, teams){
if(err){
// ...
}else if(teams){
// ...
}
})
来晚了,但希望能帮助其他搜索此内容的人。
唯一的选择是不使用正则表达式(因此不使用索引,对于大型数据集会非常慢)或使用正常的 $text
搜索(快速索引搜索但不部分匹配)。还有第三个选项使用更多的索引内存,但都支持部分匹配并使用索引(所以速度很快)。
您可以通过从字符串字段生成字符串数组(例如 name
)并将生成的数组存储在索引数组字段中来创建自己的“索引”(我们称之为 _nameSearch
).像这样
const getSearchArray: (str) => string[] = _str => {
const str = _str.toLowerCase();
const output = [];
let acc = "";
let accTotal = "";
str.split("").forEach(char => {
// Reset accumulator when space is encountered
// Otherwise, add the new phrase to the array
accTotal += char;
output.push(accTotal);
if (char === " ") {
acc = "";
} else {
acc += char;
output.push(acc);
}
});
return Array.from(new Set(output));
};
因此,如果 name
值为“选项”,_nameSearch
将是 ["o", "op", "opt", "opti", "option"]
那么您可以索引 _nameSearch
。所以你的架构看起来像这样:
const schema = new Schema(
{
name: String,
_nameSearch: { type: [String], index: true },
...
}
);
查询 name
字段就像 db.collection.find({ _nameSearch: SEARCH_STRING })
一样简单。而且您将能够找到部分匹配项并且还可以使用索引(因此搜索速度非常快)。但是,您将为 name
字段使用更大一点的索引,因此这是一种权衡,但也是一个值得考虑的可行选择。