【问题标题】:Cloudant - Lucene range search using numbers stored as textCloudant - 使用存储为文本的数字进行 Lucene 范围搜索
【发布时间】:2015-12-14 14:09:29
【问题描述】:

我在 Cloudant 中有许多文档,它们的 ID 字段类型为字符串。 ID 可以是一个简单的字符串,例如“aaa”、“bbb”或存储为文本的数字,例如“111”、“222”等。我需要能够使用上面的字段进行全文搜索,但是我遇到了一些问题。

假设我有两个文档,ID="aaa" 和 ID="111",然后使用查询进行搜索:

  • ID:aaa
  • ID:“aaa”
  • ID:[aaa TO zzz]
  • ID:["aaa" 到 "zzz"]

按预期返回第一个文档

  • ID:111

什么都不返回,但是

  • ID:“111”

返回第二个文档,所以至少有办法检索它。

不幸的是,在搜索范围时:

  • ID:[111 到 999]
  • ID:[“111”到“999”]

我没有得到任何结果,而且我不知道如何解决这个问题。这种情况有什么特殊的语法吗?

更新:

索引函数:

function(doc){
  if(!doc.ID) return;
  index("ID", doc.ID, { index:'not_analyzed_no_norms', store:true });
}

将索引更改为 analyzed 没有帮助。 Analyzer 本身是 keyword,但更改为 standard 也无济于事。

更新 2

只是为了添加更多上下文,因为我认为我错过了一个关键点。我正在索引的字段将使用范围进行搜索,并且最小值和最大值都可以由用户提供。因此,其中一个可能是存储为字符串的数字,而另一个是标准的非数字文本。例如搜索 ID >= "11" 和 ID

假设数据库包含 ID 为“1”、“5”、“alpha”、“beta”、“gamma”的文档,此查询应返回“5”、“alpha”、“beta”。请注意实际上应该返回“5”,因为字符串“5”大于字符串“11”。

【问题讨论】:

  • 你有机会分享你的地图功能吗?
  • 没有地图功能,因为这是全文索引。问题现已更新,并包含索引函数体。
  • @ArekDygas 你能评论一下为什么你想对字符串进行这种范围查询吗?在我看来,如果排序和查询范围很重要,那么您将使用数值。
  • @Raj 如果不提​​供系统的详细描述,很难解释全部目的。简而言之,我必须查询的字段由用户填写,可以在其中输入任何内容,无论是 ABCDEF、32342、)(*^@% 还是任何其他值。然后另一个用户可能会发出命令来搜索这个字段,提供单个值(用于完全匹配)或两个值(用于范围)。如果我无法解决此问题,那么我将不得不考虑对用户输入的值进行预处理,但我如果可能的话,我希望避免这种情况,因为这可能会被证明是不平凡的。
  • @ArekDygas 也许您的用例更像是邻近搜索而不是范围搜索?范围意味着找到“介于两者之间”的东西,听起来这个概念在这里并不适用。而文本邻近度是此类搜索的最佳选择。

标签: lucene cloudant


【解决方案1】:

我们的团队刚刚找到了一个临时解决方案。我们设法通过添加一些任意字符来获得正确的结果,例如'a' 为上限值,并通过引入额外的搜索词,排除 ID 介于上限值和上限值 + 'a' 之间的文档。

搜索范围时

ID:[X 到 Y]

实际查询是

(ID:[X TO Ya] AND -ID:{Y TO Ya])

例如,要查找 ID 介于 23 和 758 之间的文档,我们执行

(ID:[23 TO 758a] 和 -ID:{758 TO 758a])。

【讨论】:

    【解决方案2】:

    首先,我建议使用关键字分析器,这样您就可以在索引和搜索期间控制正确的标记化。

    "analyzer": "keyword",
    "index": "function(doc){\n  if(!doc.ID) return;\n  index(\"ID\", doc.ID, {store:true });\n}
    

    要检索带有 _id "111" 的文档,请使用以下范围查询:

    curl -X GET "http://.../facetrangetest/_design/ddoc/_search/f?q=ID:\[111%20TO%A\]" 
    

    如果您使用查询q=ID:\[111%20TO%20999\],Cloudant 搜索看到两个范围大小的数字,会将其解释为 NumericRangeQuery;并且由于您的“111” ID 是一个字符串,因此它不会成为返回结果的一部分。在查询 [111%20TO%20A] 中包含一个字符串,会使 Cloudant 将其解释为对字符串的范围查询。

    【讨论】:

    • 我实际上使用关键字分析器。关于 [111 TO A] - 这行得通,但不幸的是在我的情况下无济于事,因为我将无法搜索像 2 TO 123 这样的范围...我认为 Cloudant 应该根据实际情况来解释范围类型字段类型,但显然这不是它的工作方式......
    • 无法根据实际字段类型解释范围类型,因为无法知道字段类型,因为 CouchDb 和 Apache Lucene 可能具有相同字段名称的不同类型。跨度>
    【解决方案3】:

    您可以像这样返回两个文档:

    q=ID:["111" TO "CCC"]
    

    这是一个实际的工作示例:

    https://rajsingh.cloudant.com/facetrangetest/_design/ddoc/_search/f?q=ID:[%22111%22%20TO%20%22CCC%22]

    我发现了一些古怪的东西。似乎仅当至少一个范围值是字符串时,对字符串的范围查询才有效。查询ID:["111" TO "555"] 也不会返回任何内容,所以这可能以某种方式解析为数字查询?可能是一个错误。

    【讨论】:

    • 是的 - ["111" TO "CCC"] 会起作用,但是,正如在评论 Mayya Sharipova 的回答中指出的那样,对我的情况没有帮助......不幸的是,我也认为这是一个错误。
    【解决方案4】:

    这也可以在查询中使用正则表达式来实现。这条线:

    curl -X POST "https://.../facetrangetest/_design/ddoc/_search/f" -d '{"q":"ID:/<23-758>/"}' | jq .

    该正则表达式表示检索ID字段从23到758的所有文档。斜杠://用于包围正则表达式;区间包含在 <> 内。

    【讨论】:

    • 我认为这只适用于数字,所以很遗憾它不能满足我的需求......
    • 嗯。当我将查询更改为 // 时,我得到“位置 4 的间隔语法错误”。用双引号 (//) 将文本括起来也无济于事(第 6 位错误)。您能否分享一个适用于字符串的示例查询?
    • +1 我刚刚重新阅读了我原来的问题,现在我明白了你回答的重点。我稍微更新了一个问题,但即使没有更新,正则表达式间隔在我的情况下也无济于事,因为您的查询不会返回 ID 为“5555”的文档。对于数字来说它可以,但不幸的是对于文本它不是......
    • 哦,考虑到您的领域中既有数字又有字符串,目前唯一的解决方案就是您自己提出的解决方案。为此 +1
    猜你喜欢
    • 2011-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-03
    • 1970-01-01
    • 1970-01-01
    • 2019-10-31
    相关资源
    最近更新 更多