如何在couchdb中创建“like”过滤器视图

时间:2011-04-01 06:33:08

标签: javascript couchdb

这是我在sql中需要的一个例子:

  

SELECT name FROM使用WHERE名称LIKE %bro%

如何在couchdb中创建类似的视图?

7 个答案:

答案 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,ElasticSearchSQLite'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;对设计文档起作用以处理视图的结果:

&#13;
&#13;
{
  "_id": "_design/...",
  "views": {
    "employees": "..."
  },
  "lists": {
    "by_name": "..."
  }
}
&#13;
&#13;
&#13;

附加到&#34; by_name&#34;的功能功能,应该是这样的:

&#13;
&#13;
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;
&#13;
&#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 } )

一些注意事项

  1. 显然,根据differentVersions返回的内容,数组可以非常快。您可能会在某个时刻达到后期数据限制,或者可能会导致查找速度变慢。

  2. 结果与differentVersions一样好,可以猜测这个人的拼写意图。显然,这个功能可以像你想的那样简单或复杂。在这个例子中,我尝试了两种策略,a)删除了一个字母并将其推出,并且b)用所有其他字母替换了位置n处的字母。因此,如果有人一直在寻找“兄弟”但输入“gro”或“bri”甚至“bgro”,differentVersions会在某些时候将其置换为“兄弟”。

  3. 虽然不理想,但它仍然很快,因为查看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()?