这是我在sql中需要的一个例子:
SELECT name FROM使用WHERE名称LIKE %bro%
如何在couchdb中创建类似的视图?
答案 0 :(得分:13)
简单的答案是CouchDB视图并不理想。
更复杂的答案是,这种类型的查询在典型的SQL引擎中往往效率非常低,因此如果您批准将与任何解决方案进行权衡,那么CouchDB实际上会带来好处让你选择权衡。
1。 SQL方式
执行SELECT ... WHERE name LIKE %bro%
时,我熟悉的所有SQL引擎都必须执行所谓的“全表扫描”。这意味着服务器读取相关表中的每一行,然后强制扫描该字段以查看它是否匹配。
您可以使用$regex
operator使用Mango查询在CouchDB 2.x中执行此操作。对于基本情况,查询看起来像这样:
{"selector":{
"name": {
"$regex": "bro"
}
}}
似乎没有任何选项暴露出区分大小写等,但您可以将其扩展为仅匹配开头/结尾或更复杂的模式。如果您还可以通过其他(可索引)字段运算符限制查询,则可能有助于提高性能。正如文档警告:
正则表达式不适用于索引,因此不应将它们用于过滤大型数据集。 [...]
您也可以使用temporary view:
在CouchDB 1.x中进行全面扫描POST /some_database/_temp_view
{"map": "function (doc) { if (doc.name && doc.name.indexOf('bro') !== -1) emit(null); }"}
这将查看数据库中的每个文档,并为您提供匹配文档的列表。您可以调整地图函数以匹配文档类型,或者使用某个键进行排序 - emit(doc.timestamp)
- 或某些对您的目的有用的数据值 - emit(null, doc.name)
。
2。 “大量可用磁盘空间”方式
根据您的源数据大小,您可以创建一个索引,将每个可能的“内部字符串”作为其永久(磁盘上)视图键发出。也就是说,对于像“Dobros”这样的名字,你会emit("dobros"); emit("obros"); emit("bros"); emit("ros"); emit("os"); emit("s");
。然后,对于像'%bro%'这样的术语,您可以使用startkey="bro"&endkey="bro\uFFFF"
查询您的视图,以获取所有出现的查找字词。您的索引大约是文本内容平方的大小,但是如果您需要以比上面的完整数据库扫描更快的速度执行任何“查找字符串”并拥有可能有效的空间。尽管如此,为substring searching设计的数据结构可以为您提供更好的服务。
这也带给我们......
3。 全文搜索方式
您可以使用CouchDB插件(couchdb-lucene现在通过Dreyfus/Clouseau获取2.x,ElasticSearch,SQLite's FTS)来为您的文档生成辅助的面向文本的索引
请注意,大多数全文搜索索引don't naturally support都是任意通配符前缀,可能出于与上面所见类似的空间效率原因。通常全文搜索并不意味着“暴力二元搜索”,而是“字搜索”。但是,YMMV,请查看全文引擎中可用的选项。
如果你真的不需要在字段中找到“bro” where ,你可以通过在各种语言环境中拆分来实现基本的“以X开头的单词”搜索和常规的CouchDB视图 - 特定的单词分隔符,并省略这些“单词”作为您的视图键。这将比上述更有效,按比例缩放到索引的数据量。
答案 1 :(得分:4)
不幸的是,使用LIKE %...%
进行搜索并不是CouchDB Views的工作方式,但是您可以通过安装couchdb-lucene来完成大量的搜索功能,它是一个全文搜索引擎,可以在您的上创建索引您可以使用./ / p>进行更复杂搜索的数据库
在没有任何第三方工具的情况下,为给定密钥“搜索”数据库的典型方法是创建一个视图,该视图将您要查找的值作为密钥发出。在您的示例中:
function (doc) {
emit(doc.name, doc);
}
这将输出数据库中所有名称的列表。
现在,您将根据密钥的第一个字母“搜索”。例如,如果您要搜索以“bro”开头的名称。
/db/_design/test/_view/names?startkey="bro"&endkey="brp"
注意我拿了搜索参数的最后一个字母,并“递增”了它中的最后一个字母。同样,如果您想要执行搜索而不是聚合统计信息,则应使用全文搜索引擎,如lucene。 (见上文)
答案 2 :(得分:1)
我为我的问题找到了一个简单的查看代码 ...
如果我将一个关键句分成一个关键词,从这个视图代码{
“getavailableproduct”:
{ “map”:“function(doc){
var prefix = doc ['productid']。match(/ [A-Za-z0-9] + / g);
if(prefix)
for(var pre in prefix){emit(prefix [pre],null);}
}“
}
}
我可以打电话
?键= <强> “[SEARCH_KEYWORD]”强>
但我需要更复杂的代码,因为如果我运行此代码我只能找到我输入的单词(例如:吃,食物等)......
但是如果我想输入的不是一个完整的单词(例如:来自eat,或foo来自food),那么代码不起作用..
答案 3 :(得分:1)
我知道这是一个老问题,但是:如何使用&#34;列表&#34;功能?您可以拥有所有普通视图,然后添加一个&#34;列表&#34;对设计文档起作用以处理视图的结果:
{
"_id": "_design/...",
"views": {
"employees": "..."
},
"lists": {
"by_name": "..."
}
}
&#13;
附加到&#34; by_name&#34;的功能功能,应该是这样的:
function (head, req) {
provides('json', function() {
var filtered = [];
while (row = getRow()) {
// We can retrive all row information from the view
var key = row.key;
var value = row.value;
var doc = req.query.include_docs ? row.doc : {};
if (value.name.indexOf(req.query.name) == 0) {
if (req.query.include_docs) {
filtered.push({ key: key, value: value, doc: doc});
} else {
filtered.push({ key: key, value: value});
}
}
}
return toJSON({ total_rows: filtered.length, rows: filtered });
});
}
&#13;
当然,您也可以使用正则表达式。它不是一个完美的解决方案,但它对我有用。
答案 4 :(得分:0)
您可以正常发出文件。 emit(doc.name, null);
我会在toLowerCase()
上抛出name
以消除区分大小写。
然后用一大串键查询视图,看看是否有“喜欢”查询的内容。
keys = differentVersions("bro"); // returns ["bro", "br", "bo", "ro", "cro", "dro", ..., "zro"]
$.couch("db").view("employeesByName", { keys: keys, success: dealWithIt } )
一些注意事项
显然,根据differentVersions
返回的内容,数组可以非常快。您可能会在某个时刻达到后期数据限制,或者可能会导致查找速度变慢。
结果与differentVersions
一样好,可以猜测这个人的拼写意图。显然,这个功能可以像你想的那样简单或复杂。在这个例子中,我尝试了两种策略,a)删除了一个字母并将其推出,并且b)用所有其他字母替换了位置n处的字母。因此,如果有人一直在寻找“兄弟”但输入“gro”或“bri”甚至“bgro”,differentVersions
会在某些时候将其置换为“兄弟”。
虽然不理想,但它仍然很快,因为查看Couch的b-tree很快。
答案 5 :(得分:0)
您可以使用正则表达式。根据此table,您可以编写类似这样的内容,以返回包含&#34; SMS&#34;。
的任何ID{
"selector": {
"_id": {
"$regex": "sms"
}
}
}
您可以使用的基本正则表达式包括
"^sms" roughly to LIKE "%sms"
"sms$" roughly to LIKE "sms%"
您可以阅读有关正则表达式here
的更多信息答案 6 :(得分:-1)
为什么我们只能在视图中使用indexOf()?