简单的答案是CouchDB视图并不适合这种情况。 更复杂的答案是,这种类型的查询在典型的SQL引擎中也往往效率非常低,因此,如果您承认 * 任何 * 解决方案都会有折衷,那么CouchDB实际上具有允许您选择折衷的好处。 1.SQL方法 当您执行SELECT ... WHERE name LIKE %bro%时,我所熟悉的所有SQL引擎都必须执行所谓的“全表扫描”,这意味着服务器读取相关表中的每一行,并对字段进行暴力扫描以查看是否匹配。 您可以在CouchDB 2.x中使用$regex操作符对Mango查询执行此操作。
POST /some_database/_temp_view
{"map": "function (doc) { if (doc.name && doc.name.indexOf('bro') !== -1) emit(null); }"}
这将遍历数据库中的每一个文档,并给予你一个匹配文档的列表。你可以调整map函数来匹配文档类型,或者用一个特定的排序键-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"查询视图,以获取该查找术语的所有匹配项。您的索引将近似于文本内容的大小 * squared*,但是如果你需要做一个任意的“find in string”,比上面的完全DB扫描更快,并且有足够的空间,这可能会起作用。 这也给我们带来了... 3.全文搜索方式 您可以使用CouchDB插件(couchdb-lucene现在通过Dreyfus/Clouseau for 2.x、ElasticSearch、SQLite's FTS)为文档生成一个辅助的面向文本的索引。 请注意,大多数全文搜索索引也不支持任意通配符前缀,可能是出于类似的空间效率原因。通常全文搜索并不意味着“蛮力二分搜索”,而是“单词搜索”。YMMV尽管如此,还是看看全文引擎中可用的选项吧。 如果你不需要在字段的任何地方找到“bro”,你可以用常规的CouchDB视图实现基本的“find a word started with X”搜索,只需要在不同的特定于区域的单词分隔符上进行拆分,并省略这些“单词”作为视图键。这将比上面的方法更高效,并与索引的数据量成比例地扩展。
7条答案
按热度按时间d6kp6zgx1#
简单的答案是CouchDB视图并不适合这种情况。
更复杂的答案是,这种类型的查询在典型的SQL引擎中也往往效率非常低,因此,如果您承认 * 任何 * 解决方案都会有折衷,那么CouchDB实际上具有允许您选择折衷的好处。
1.SQL方法
当您执行
SELECT ... WHERE name LIKE %bro%
时,我所熟悉的所有SQL引擎都必须执行所谓的“全表扫描”,这意味着服务器读取相关表中的每一行,并对字段进行暴力扫描以查看是否匹配。您可以在CouchDB 2.x中使用
$regex
操作符对Mango查询执行此操作。似乎没有提供任何区分大小写等选项,但您可以扩展它,使其仅匹配开头/结尾或更复杂的模式。如果您还可以通过其他(可索引的)字段操作符来限制查询,这可能有助于提高性能。正如文档中所警告的:
正则表达式不适用于索引,所以不应该用它们来过滤大型数据集。[...]
您也可以在CouchDB 1.x中使用临时视图进行完全扫描:
这将遍历数据库中的每一个文档,并给予你一个匹配文档的列表。你可以调整map函数来匹配文档类型,或者用一个特定的排序键-
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"
查询视图,以获取该查找术语的所有匹配项。您的索引将近似于文本内容的大小 * squared*,但是如果你需要做一个任意的“find in string”,比上面的完全DB扫描更快,并且有足够的空间,这可能会起作用。这也给我们带来了...
3.全文搜索方式
您可以使用CouchDB插件(couchdb-lucene现在通过Dreyfus/Clouseau for 2.x、ElasticSearch、SQLite's FTS)为文档生成一个辅助的面向文本的索引。
请注意,大多数全文搜索索引也不支持任意通配符前缀,可能是出于类似的空间效率原因。通常全文搜索并不意味着“蛮力二分搜索”,而是“单词搜索”。YMMV尽管如此,还是看看全文引擎中可用的选项吧。
如果你不需要在字段的任何地方找到“bro”,你可以用常规的CouchDB视图实现基本的“find a word started with X”搜索,只需要在不同的特定于区域的单词分隔符上进行拆分,并省略这些“单词”作为视图键。这将比上面的方法更高效,并与索引的数据量成比例地扩展。
uz75evzq2#
不幸的是,使用
LIKE %...%
进行搜索实际上并不是CouchDB视图的工作方式,但是您可以通过安装couchdb-lucene来实现大量的搜索功能,它是一个全文搜索引擎,可以在数据库上创建索引,您可以使用它进行更复杂的搜索。在没有任何第三方工具的情况下,在数据库中“搜索”给定键的典型方法是创建一个视图,将您要查找的值作为键发出。在您的示例中:
这将输出数据库中所有名称的列表。
现在,你将根据你键的第一个字母来“搜索”。例如,如果你正在搜索以“bro”开头的名字。
注意,我取了search参数的最后一个字母,并“递增”了其中的最后一个字母。同样,如果您想执行搜索,而不是聚集统计信息,您应该使用像lucene这样的全文搜索引擎。
du7egjpx3#
您可以使用正则表达式。根据此表,您可以编写如下代码来返回任何包含“SMS”的ID。
可以在上使用的基本正则表达式包括
你可以阅读更多关于正则表达式here
ubby3x7f4#
我发现了一个简单的查看代码为我的问题...
{
“获取可用产品”:
{“Map”:“函数(doc){
变量前缀= doc ['产品ID'].match(/[A-Za-z 0 -9]+/g);
if(前缀)
(前缀中的变量pre){ emit(前缀[pre],null);}
}”
上
}
从这个Angular 看代码如果我把一个关键句拆分成一个关键词...
?key="[搜索关键字]"
但是我需要更复杂代码,因为如果我运行这个代码,我只能找到我键入的单词(例如:吃、食物等)。
但是如果我想键入不是完整单词(例如:eat中ea,或foo中的food)代码不起作用。
soat7uwm5#
我知道这是个老问题,但是:使用“list”函数怎么样?您可以拥有所有普通视图,然后在设计文档中添加“list”函数来处理视图的结果:
而附加到“by_name”函数的函数,应该是这样的:
当然,你也可以使用正则表达式。这不是一个完美的解决方案,但对我来说很有效。
deyfvvtc6#
你可以像正常一样发出你的文档。
emit(doc.name, null);
我会在name
上抛出一个toLowerCase()
来消除大小写敏感性。然后用一系列键查询视图,看看是否显示了“类似”查询的内容。
一些注意事项
1.很明显,这个数组会很快变得很大,这取决于
differentVersions
返回的内容。你可能会在某个时候达到post数据限制,或者可能会得到很慢的查找。1.结果只能像
differentVersions
一样让你猜出这个人想要拼写什么。显然,这个函数可以简单也可以复杂。在这个例子中,我尝试了两种策略,a)删除一个字母并按下它,以及B)用所有其他字母替换位置n处的字母。因此,如果有人一直在寻找“bro”,但键入了“gro”或“bri”甚至“bgro”,differentVersions
会在某个时候将其置换为“bro”。1.虽然不是理想的,它仍然是相当快的,因为在沙发的b树查找是快速的。
r1wp621o7#
为什么不能直接在view中使用indexOf()呢?