【问题标题】:How do I create a "like" filter view in CouchDB如何在 CouchDB 中创建“喜欢”过滤器视图
【发布时间】:2021-02-25 22:18:35
【问题描述】:

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

SELECT name FROM雇WHERE name LIKE %bro%

如何在 CouchDB 中创建这样的视图?

【问题讨论】:

    标签: javascript couchdb


    【解决方案1】:

    简单的答案是 CouchDB 视图不适合此。

    更复杂的答案是,这种类型的查询在典型的 SQL 引擎中也往往效率很低,因此如果您同意与 any 解决方案进行权衡,那么 CouchDB 实际上具有优势让你选择你的权衡。

    1。 SQL 方法

    当您执行SELECT ... WHERE name LIKE %bro% 时,我熟悉的所有 SQL 引擎都必须执行所谓的“全表扫描”。这意味着服务器读取相关表中的每一行,然后暴力扫描字段以查看是否匹配。

    您可以在 CouchDB 2.x 中通过使用 $regex operator 的 Mango 查询来执行此操作。对于基本情况,查询看起来像这样:

    {"selector":{
      "name": {
        "$regex": "bro"
      }
    }}
    

    似乎没有为区分大小写等提供任何选项,但您可以将其扩展为仅匹配开头/结尾或更复杂的模式。如果您还可以通过其他一些(可索引的)字段运算符来限制您的查询,那可能会提高性能。正如文档警告的那样:

    正则表达式不适用于索引,因此它们不应用于过滤大型数据集。 […]

    您也可以在 CouchDB 1.x 中进行全面扫描,使用 temporary view:

    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,但如果您需要比上面的完整数据库扫描更快地执行任意“在字符串中查找”并且有空间,这可能会起作用。不过,为substring searching 设计的数据结构会更好地为您服务。

    这也给我们带来了...

    3。 全文搜索方式

    您可以使用 CouchDB 插件(couchdb-lucene 现在通过 Dreyfus/Clouseau 用于 2.x、ElasticSearchSQLite's FTS)为您的文档生成一个面向文本的辅助索引。

    请注意,大多数全文搜索索引don't naturally support 任意通配符前缀,可能是出于与我们在上面看到的空间效率类似的原因。通常全文搜索并不意味着“暴力二进制搜索”,而是“单词搜索”。不过,请查看您的全文引擎中可用的选项。

    如果您真的不需要在字段中查找“bro”任何地方,您可以使用常规 CouchDB 视图实现基本的“查找以 X 开头的单词”搜索,只需在各种区域设置上进行拆分- 特定的单词分隔符并省略这些“单词”作为您的视图键。这将比上面更有效,与索引的数据量成比例。

    【讨论】:

    • 对于答案,第 1 号。实际上我使用的是 bigcouch 而不是 couchdb,而且 bigcouch 没有临时视图...第 2 号。这是个坏主意,因为我有很多文件超过 2 个单词作为键...数字 3。我已经尝试过了,但我检查了 elasticsearch 和 couchdb-lucene 的性能真的很差(我用 apache 基准检查)
    • 我认为 CouchDB 2 没有临时视图。有没有办法通过 Mango 查询来做到这一点?
    • @wb9688 是的,Mango 查询包含一个 $regex 运算符,其性能与临时视图相似。我会更新我的答案。
    【解决方案2】:

    不幸的是,使用 LIKE %...% 进行搜索并不是 CouchDB 视图的真正工作方式,但是您可以通过安装 couchdb-lucene 来完成大量搜索功能,它是一个全文搜索引擎,可以在您的数据库上创建索引,您可以进行更复杂的搜索。

    在没有任何第三方工具的情况下“搜索”给定键的数据库的典型方法是创建一个视图,该视图发出您正在寻找的值作为键。在您的示例中:

    function (doc) {
        emit(doc.name, doc);
    }
    

    这会输出数据库中所有名称的列表。

    现在,您将根据密钥的首字母“搜索”。例如,如果您要搜索以“bro”开头的名称。

    /db/_design/test/_view/names?startkey="bro"&endkey="brp"
    

    请注意,我采用了搜索参数的最后一个字母,并“递增”了其中的最后一个字母。同样,如果您想执行搜索,而不是汇总统计信息,您应该使用像 lucene 这样的全文搜索引擎。 (见上文)

    【讨论】:

    • As suggested by kowsik,您应该避免将文档作为值发出。查询视图时使用emit(doc.name, null) 并使用include_docs=true
    • couchdb lucene 是一个正确的答案...但是我需要一个简单的代码...我想在句子中找到一个单词...而且句子很多...简单的解释是我想创建 简单的搜索引擎... whitout 插件或诸如 couchdb lucene 之类的东西...抱歉我的英语不好..
    【解决方案3】:

    您可以使用正则表达式。根据table,您可以编写类似这样的内容来返回任何包含“SMS”的 id。

    {
       "selector": {
          "_id": {
             "$regex": "sms"
          }
       }
    }
    

    您可以使用的基本正则表达式包括

    "sms$" roughly to LIKE "%sms"
    "^sms" roughly to LIKE "sms%"
    

    您可以阅读更多关于正则表达式的内容here

    【讨论】:

    • 您的正则表达式示例实际上已切换。 ^ 匹配字符串的开头,因此^sms 匹配以sms 开头的字符串,因此类似于sms%$ 匹配字符串的结尾,所以sms$ 匹配以sms 结尾的字符串,类似于%sms
    • 我刚刚修改了
    【解决方案4】:

    我为我的问题找到了一个简单的查看代码...

    {
    “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); }
                }"
           }
    }

    如果我将一个关键句子分成一个关键词,则从这个视图代码中...... 我可以打电话给

    ?key="[search_keyword]"

    但我需要更复杂的代码,因为如果我运行此代码,我只能找到我输入的单词(例如:吃、食物等)...

    但如果我想输入的不是一个完整的单词(例如:ea 来自 eat,或 foo 来自 food),则该代码不起作用..

    【讨论】:

    • 您可以在返回的密钥上使用 levenshtein 距离算法。这是否是一个好主意取决于您正在搜索的数据量。示例:github.com/lysdexia/Lookahead-Lev.
    • 进一步考虑,我认为使用我的示例不会有帮助,因为您希望在文本中进行任意搜索,而不是在映射值上“归零”。 Lucene 肯定是要走的路。您可能想看看 solr,而您正在使用它。 lucene.apache.org/solr
    【解决方案5】:

    我知道这是一个老问题,但是:使用“列表”函数怎么样?您可以拥有所有普通视图,然后在设计文档中添加“列表”功能来处理视图的结果:

    {
      "_id": "_design/...",
      "views": {
        "employees": "..."
      },
      "lists": {
        "by_name": "..."
      }
    }

    附加到“by_name”函数的函数应该是这样的:

    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 });
      });
    }

    当然,您也可以使用正则表达式。这不是一个完美的解决方案,但它对我有用。

    【讨论】:

      【解决方案6】:

      您可以像平常一样发出您的文档。 emit(doc.name, null); 我会在 name 上添加一个 toLowerCase() 以消除区分大小写。

      然后使用一系列键查询视图,看看是否出现了“类似”查询的内容。

      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 处的字母替换为所有其他字母。因此,如果有人一直在寻找“bro”,但输入了“gro”或“bri”甚至“bgro”,differentVersions 会在某个时候将其替换为“bro”。

      3. 虽然不理想,但仍然相当快,因为​​在 Couch 的 b 树中查找很快。

      【讨论】:

        【解决方案7】:

        为什么我们不能只在视图中使用 indexOf()?

        【讨论】:

        • 视图需要返回或多或少的静态行列表。这些将按与行(发出的第一个参数)一起返回的主键进行排序。您可以通过 order/startstring/ 查询第一个参数,如其他答案所示。但是 indexOf 会是动态的,因为它的参数之一仅在使用查询/视图时可用
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-12-29
        • 1970-01-01
        • 2018-11-04
        • 1970-01-01
        • 1970-01-01
        • 2020-10-20
        • 1970-01-01
        相关资源
        最近更新 更多