在elasticsearch上查找具有空字符串值的文档

时间:2014-08-29 05:03:57

标签: elasticsearch

我一直在尝试使用elasticsearch过滤那些在其正文中包含空字符串的文档。到目前为止,我没有运气。

在继续之前,我应该提一下,我已经尝试过围绕Interwebz和StackOverflow的很多“解决方案。”

因此,下面是我正在尝试运行的查询,后跟其对应项:

{
    "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"}
            }
        }
    }
}

以上都没有奏效。当我确定存在包含空字符串字段的记录时,我得到一个空结果集。

如果有人能给我任何帮助,我将非常感激。

谢谢!

12 个答案:

答案 0 :(得分:19)

如果您使用的是默认分析器(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: ""
                }
            }
        ]
    }
}

答案 1 :(得分:10)

即使使用默认分析器,您也可以进行此类搜索:使用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->脚本,如https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html

答案 2 :(得分:4)

对于那些使用弹性搜索5.2或以上的人,仍然卡住了。最简单的方法是使用关键字类型正确地重新索引数据。然后所有空值搜索都有效。像这样:

"query": {
    "term": {"MY_FIELD_TO_SEARCH": ""}
}

实际上,当我重新索引数据库并重新运行查询时。它工作=)

问题是我的字段是type:text而不是关键字。将索引更改为关键字并重新编制索引:

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"
 }
}'

我希望这可以帮助那些因为找到那些空值而陷入困境的人。

答案 3 :(得分:2)

为了在文档中找到一个字段的空字符串,它与字段的映射高度相关,换句话说,它与index / analyzer设置高度相关。

如果其索引为not_analyzed,这意味着令牌只是空字符串,您可以使用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

顺便说一下,我查看你提供的命令,看来你不想要空字符串文件。 以上所有命令只是为了找到这些,所以只需将其放入must_not部分bool查询即可。 我的ES是1.0.1。


对于ES 1.3.0,目前我提供的要点找不到空字符串。似乎有报道:https://github.com/elasticsearch/elasticsearch/issues/7348。让我们等一下,看看它是怎么回事。

无论如何,它还提供了另一个命令来查找

  

{“query”:{       “过滤”:{         “过滤器”:{           “不是”:{             “过滤器”:{               “范围”: {                 “名称”: {                 }               }             }           }         }       }}

name是用于查找空字符串的字段名称。我在ES 1.3.2上测试了它。

答案 4 :(得分:2)

我正在使用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 ,例如索引'business'上的'city',您需要输入类型名称'record':

PUT business/_mapping/record
{
    "properties": {
        "city": {
          "type": "text",
          "fielddata": true
        }
      }
}

答案 5 :(得分:1)

使用Lucene查询字符串语法进行

  

q =!(yourfield.keyword:“”)

请参见Elastic Search参考https://www.elastic.co/guide/en/elasticsearch/reference/6.5/query-dsl-query-string-query.html#query-string-syntax

答案 6 :(得分:0)

对于嵌套字段,请使用:

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"
                } 
            } 
        } 
    } 
}'

答案 7 :(得分:0)

我没有设法在文本字段中搜索空字符串。但是它似乎适用于类型关键字的字段。所以我建议如下:

    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" : ""}}}
             }
}

答案 8 :(得分:0)

您需要通过在字段名称中添加 .content 来触发关键字索引器。根据原始索引的设置方式,以下“仅适用于”我使用AWS ElasticSearch v6.x。

  

获取/my_idx/_search?q=my_field.content:“”

答案 9 :(得分:0)

如果您不想或无法重新编制索引,则可以使用另一种方法。 :-)

您可以使用否定运算符和通配符来匹配任何非空字符串*

GET /my_index/_search?q=!(fieldToLookFor:*)

答案 10 :(得分:0)

在这里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": "*"
          }
        }
      ]
    }
  }
}

答案 11 :(得分:0)

我正在尝试查找空字段(在具有动态映射的索引中)并将其设置为默认值,以下内容对我有用

  

请注意,这是在弹性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"
          }
        }
      ]
    }
  }
}

感谢为此线程做出贡献的每一个人,我能够解决我的问题