在 elasticsearch 上查找具有空字符串值的文档
Posted
技术标签:
【中文标题】在 elasticsearch 上查找具有空字符串值的文档【英文标题】:Find documents with empty string value on elasticsearch 【发布时间】:2014-08-29 05:03:56 【问题描述】:我一直在尝试使用 elasticsearch 过滤那些正文中包含空字符串的文档。到目前为止,我没有运气。
在我继续之前,我应该提一下,我已经尝试了 许多 在 Interwebz 和 *** 上传播的“解决方案”。
所以,下面是我尝试运行的查询,然后是对应的查询:
"query":
"filtered":
"filter":
"bool":
"must_not": [
"missing":
"field":"_textContent"
]
我还尝试了以下方法:
"query":
"filtered":
"filter":
"bool":
"must_not": [
"missing":
"field":"_textContent",
"existence":true,
"null_value":true
]
还有以下内容:
"query":
"filtered":
"filter":
"missing": "field": "_textContent"
以上都不起作用。当我确定存在包含空字符串字段的记录时,我得到一个空结果集。
如果有人可以为我提供任何帮助,我将非常感激。
谢谢!
【问题讨论】:
对于 ES,它总是建议提及版本,因为即使是次要版本也有很大差异。 lucene/kql 查询:yourfield.keyword:""
有效。来自以下答案之一***.com/a/54046098/52074
【参考方案1】:
如果您使用的是默认分析器 (standard
),则它无法分析它是否为空字符串。因此,您需要逐字索引该字段(未分析)。这是一个例子:
添加一个映射来索引未标记的字段,如果您还需要索引字段的标记副本,您可以使用Multi Field 类型。
PUT http://localhost:9200/test/_mapping/demo
"demo":
"properties":
"_content":
"type": "string",
"index": "not_analyzed"
接下来,索引几个文档。
/POST http://localhost:9200/test/demo/1/
"_content": ""
/POST http://localhost:9200/test/demo/2
"_content": "some content"
执行搜索:
POST http://localhost:9200/test/demo/_search
"query":
"filtered":
"filter":
"term":
"_content": ""
返回带有空字符串的文档。
took: 2,
timed_out: false,
_shards:
total: 5,
successful: 5,
failed: 0
,
hits:
total: 1,
max_score: 0.30685282,
hits: [
_index: test,
_type: demo,
_id: 1,
_score: 0.30685282,
_source:
_content: ""
]
【讨论】:
但是我已经有很多文档已经存储在 elasticsearch 中(大约 50k)。 AFAIK,更新映射信息需要重新索引文档。是这样吗,或者此映射更新将适用于我当前的文档? 如果您更新映射,您将需要重新索引。看看重新索引插件:github.com/karussell/elasticsearch-reindex 此外,此策略要求我存储该字段的两份副本,一份已标记化,另一份作为原始副本。这个 _textContent 字段实际上来自通过 OCR 运行的 PDF 文件,因此它可以变得非常大。我认为存储两份副本可能有点太多了。 我想我现在要使用客户端解决方案。不过谢谢:) 如果字段的映射是关键字怎么办?分析了吗?【参考方案2】:在这里找到解决方案https://github.com/elastic/elasticsearch/issues/7515 它无需重新索引即可工作。
PUT t/t/1
"textContent": ""
PUT t/t/2
"textContent": "foo"
GET t/t/_search
"query":
"bool":
"must": [
"exists":
"field": "textContent"
],
"must_not": [
"wildcard":
"textContent": "*"
]
【讨论】:
适用于 ES v. 5.6【参考方案3】:即使使用默认分析器,您也可以进行这种搜索:使用script filter,它速度较慢但可以处理空字符串:
curl -XPOST 'http://localhost:9200/test/demo/_search' -d '
"query":
"filtered":
"filter":
"script":
"script": "_source._content.length() == 0"
'
它会将带有空字符串的文档作为_content返回,而不需要特殊映射
正如@js_gandalf 所指出的,这在 ES>5.0 中已被弃用。相反,您应该使用:query->bool->filter->script as in https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html
【讨论】:
对不起...但这不起作用。 "error":"root_cause":["type":"parsing_exception","reason":"没有为 [filtered] 注册 [query]","line":4,"col":14], "type":"parsing_exception","reason":"no [query] 为 [filtered] 注册","line":4,"col":14,"status":400 我使用的是 elastic 5.2,我认为这会影响正在发生的事情 您好@js_gandalf,这就是 IT 的问题,有时 2 年后 api 中断 :-) 版本 0.90 已回答。我不知道 SO 的用途是什么,我应该删除我的答案吗?无论如何,感谢您注意到这一点。 @VrigileD 没关系。我在这件事上被难住了一段时间。它杀了我!所以我现在必须重新索引我的整个数据库才能让它工作?我正在使用 5.2 最新版本的弹性搜索。 我现在没有使用 ES,但我认为过滤已被弃用,现在你应该使用 query->bool->filter->script,类似于elastic.co/guide/en/elasticsearch/reference/current/… 我刚刚重新索引整个数据库。然后它起作用了!发布答案。对于 ES > 5.2【参考方案4】:对于那些使用弹性搜索 5.2 或更高版本但仍然卡住的人。最简单的方法是使用关键字类型正确地重新索引您的数据。然后所有对空值的搜索都起作用了。像这样:
"query":
"term": "MY_FIELD_TO_SEARCH": ""
实际上,当我重新索引我的数据库并重新运行查询时。成功了=)
问题是我的字段是类型:文本而不是关键字。将索引更改为关键字并重新索引:
curl -X PUT https://username:password@host.io:9200/mycoolindex
curl -X PUT https://user:pass@host.io:9200/mycoolindex/_mapping/mycooltype -d '
"properties":
"MY_FIELD_TO_SEARCH":
"type": "keyword"
,
'
curl -X PUT https://username:password@host.io:9200/_reindex -d '
"source":
"index": "oldindex"
,
"dest":
"index": "mycoolindex"
'
我希望这可以帮助那些像我发现那些空值一样陷入困境的人。
【讨论】:
也适用于巢。需要逐字添加到查询中。【参考方案5】:为了在您的文档中找到一个字段的空字符串,它与该字段的映射高度相关,换句话说,它的index
/analyzer
设置。
如果它的索引是not_analyzed
,也就是说token就是一个空字符串,你可以直接用term
查询来找到它,如下:
"from": 0, "size": 100, "query":"term": "name":""
否则,如果index
设置为analyzed
并且我相信大多数分析器会将空字符串视为空值所以
您可以使用过滤器查找空字符串。
"filter": "missing": "existence": true, "field": "name", "null_value": true, "query": "match_all":
这是您可以参考的 gist 脚本:https://gist.github.com/hxuanji/35b982b86b3601cb5571
顺便说一句,我检查了您提供的命令,看来您不想要空字符串文档。
而我上面的所有命令只是为了找到这些,所以只需将其放入bool
查询的must_not
部分就可以了。
我的 ES 是 1.0.1。
对于 ES 1.3.0,目前我提供的 gist 找不到空字符串。似乎已经报道了:https://github.com/elasticsearch/elasticsearch/issues/7348。让我们拭目以待吧。
不管怎样,它还提供了另一个命令来查找
"查询": “过滤”: “筛选”: “不是”: “筛选”: “范围”: “姓名”:
name
是查找空字符串的字段名称。我已经在 ES 1.3.2 上测试过了。
【讨论】:
不,实际上我想查找在该特定字段中具有空字符串的所有文档。我可能问错了。顺便说一句,在我对该字段进行全文搜索时会分析索引。 好的,如果是这样,第二个命令就可以了。(检查要点)顺便说一句,如果该字段用于全文搜索,我认为not_analyzed
设置可能对您没有用.
我已经尝试过您的 gist 查询,但它不起作用,它显然不会将空字符串视为 null,这很奇怪。我想我会在客户端实现这个。我不知道这是否有意义,但在我看来 ES 缺少一个“空”过滤器......无论如何,感谢您的帮助!
嗨,我刚刚对 ES 1.3.2 进行了快速测试。我提供的要点不像你说的那样工作。虽然它适用于 ES 1.0.1,目前我在我的项目中使用它。我不确定这是否是错误。我会做更多的测试。
嗨@PauloVictor 我想你可能知道。这是github.com/elasticsearch/elasticsearch/issues/7348 报告的错误,它报告了 ES 1.3.0。但是官方提供了一些其他的命令来得到你想要的,检查我上面的编辑。【参考方案6】:
我使用的是 Elasticsearch 5.3,但在上面的一些答案中遇到了问题。
以下机构对我有用。
"query":
"bool" :
"must" :
"script" :
"script" :
"inline": "doc['city'].empty",
"lang": "painless"
注意:您可能需要为文本字段启用 fielddata,默认情况下它是禁用的。虽然我会在这样做之前阅读:https://www.elastic.co/guide/en/elasticsearch/reference/current/fielddata.html。
为字段启用 fielddata,例如索引“企业”上的“城市”,您需要类型名称“记录”:
PUT business/_mapping/record
"properties":
"city":
"type": "text",
"fielddata": true
【讨论】:
【参考方案7】:OR 使用 lucene 查询字符串语法
q=yourfield.keyword:""
请参阅弹性搜索参考https://www.elastic.co/guide/en/elasticsearch/reference/6.5/query-dsl-query-string-query.html#query-string-syntax
【讨论】:
【参考方案8】:如果您不想或无法重新索引,还有另一种方法。 :-)
您可以使用否定运算符和通配符来匹配任何非空字符串 *
GET /my_index/_search?q=!(fieldToLookFor:*)
【讨论】:
但它只返回此字段为空的文档。等于"query":"bool":"must_not":"exists":"field":"address"
【参考方案9】:
对于嵌套字段使用:
curl -XGET "http://localhost:9200/city/_search?pretty=true" -d '
"query" :
"nested" :
"path" : "country",
"score_mode" : "avg",
"query" :
"bool":
"must_not":
"exists":
"field": "country.name"
'
注意:路径和字段共同构成搜索。根据需要进行更改以使您工作。
对于常规字段:
curl -XGET 'http://localhost:9200/city/_search?pretty=true' -d'
"query":
"bool":
"must_not":
"exists":
"field": "name"
'
【讨论】:
他们要求一个确实存在但包含一个空字符串的字段。must_not exists
仅适用于空数组和空值,因为从技术上讲它们没有被索引。空字符串是。【参考方案10】:
我没有设法在文本字段中搜索空字符串。但是,它似乎适用于类型关键字的字段。所以我建议如下:
delete /test_idx
put test_idx
"mappings" :
"testMapping":
"properties" :
"tag" : "type":"text",
"content" : "type":"text",
"fields" :
"x" : "type" : "keyword"
put /test_idx/testMapping/1
"tag": "null"
put /test_idx/testMapping/2
"tag": "empty",
"content": ""
GET /test_idx/testMapping/_search
"query" :
"match" : "content.x" : ""
【讨论】:
【参考方案11】:您需要通过将 .content 添加到您的字段名称来触发关键字索引器。根据原始索引的设置方式,以下使用 AWS ElasticSearch v6.x 对我“有效”。
GET /my_idx/_search?q=my_field.content:""
【讨论】:
【参考方案12】:我正在尝试查找空字段(在具有动态映射的索引中)并将它们设置为默认值,以下对我有用
注意这是在 elastic 7.x 中
POST <index_name|pattern>/_update_by_query
"script":
"lang": "painless",
"source": """
if (ctx._source.<field name>== "")
ctx._source.<field_name>= "0";
else
ctx.op = "noop";
"""
我关注了线程中的一个响应,并在下面提出了它会做同样的事情
GET index_pattern*/_update_by_query
"script":
"source": "ctx._source.field_name='0'",
"lang": "painless"
,
"query":
"bool":
"must": [
"exists":
"field": "field_name"
],
"must_not": [
"wildcard":
"field_name": "*"
]
我也在尝试在索引中找到没有该字段的文档并为它们添加一个值
这个帖子的一个回复帮助我想出了下面
GET index_pattern*/_update_by_query
"script":
"source": "ctx._source.field_name='0'",
"lang": "painless"
,
"query":
"bool":
"must_not": [
"exists":
"field": "field_name"
]
感谢为这个帖子做出贡献的每一个人,我能够解决我的问题
【讨论】:
以上是关于在 elasticsearch 上查找具有空字符串值的文档的主要内容,如果未能解决你的问题,请参考以下文章
如何判断具有空字符串值的 python 字符串变量在初始化时是使用单引号还是双引号?