elasticsearch must_not 条款条款无效

elasticsearch must_not terms clause is not working

看看这个 elasticsearch 查询:

{
    "query": {
        "bool": {
            "must_not": {
                "terms": {
                    "element_type": [
                        "TYPE1",
                        "TYPE2",
                        "TYPE3"
                    ]
                }
            },
            "should": [
                {
                    "match_phrase": {
                        "myfield1": {
                            "query": "mykeyword"
                        }
                    }
                },
                {
                    "match_phrase": {
                        "myfield2": {
                            "query": "mykeyword"
                        }
                    }
                }
            ]
        }
    }
}

我正在使用 6.2.4 版本的弹性搜索。

一切正常,但最后几天我在 element_type 字段中得到了 TYPE1、TYPE2、TYPE3 值的结果。

没有任何改变...

你知道这个问题吗?

谢谢

* 编辑 *

我创建了一个 php 脚本来演示这个问题。 我在全新的弹性搜索安装中安装了 运行:

<?php

    function insert($doc_type,$nb)
    {
        for ($id=1;$id<=$nb;$id++)
        {
            $url = "http://localhost:9200/idx5/doc/".$doc_type.'-'.$id;
            // echo $url."\n";

            $ch = curl_init();

            $query = array(
                "id" => $id,
                "element_type" => $doc_type,
                "title" => 'test '.$doc_type.' '.$id
            );

            $query = json_encode($query);

            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
            curl_setopt($ch, CURLOPT_POSTFIELDS, $query);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json'));
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 0);
            $result = curl_exec($ch);
            curl_close($ch);

            $result = json_decode($result, true);
            if ($result['_shards']['successful']!='1')
            {
                echo $query;
                print_r($result);
                return false;
            }
        }
    }

    insert('TYPE1',6);
    insert('TYPE2',100);


    $ch = curl_init();
    $method = "GET";
    $url = "127.0.0.1/idx5/_search?size=600";
    $query = '{
        "query": {
            "bool": {
                "must_not": {
                    "term" : { "element_type" : "TYPE1" }
                },
                "should": [
                    {
                        "match_phrase": {
                            "title": {
                                "query": "test"
                            }
                        }
                    }
                ]
            }
        }
    }';

    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_PORT, 9200);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, strtoupper($method));
    curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
    curl_setopt($ch, CURLOPT_POSTFIELDS, $query);

    $result = curl_exec($ch);
    curl_close($ch);
    $result = json_decode($result, true);

    foreach ($result['hits']['hits'] as $res) 
    {
        $type = $res["_source"]["element_type"];
        echo $type."\n";
        if ($type=="TYPE1")
        {
            print_r($res);
            die;
        }
    }

?>

这是我的脚本的输出:

Array
(
    [_index] => idx5
    [_type] => doc
    [_id] => TYPE1-1
    [_score] => 0.0023501774
    [_source] => Array
        (
            [id] => 1
            [element_type] => TYPE1
            [title] => test TYPE1 1
        )

)

我的结果中不应该出现 TYPE1 element_type...

我没有映射。我认为映射是自动创建的。

有输出:curl http://localhost:9200/idx5:

{
    "idx5": {
        "aliases": {},
        "mappings": {
            "properties": {
                "element_type": {
                    "type": "text",
                    "fields": {
                        "keyword": {
                            "type": "keyword",
                            "ignore_above": 256
                        }
                    }
                },
                "id": {
                    "type": "long"
                },
                "title": {
                    "type": "text",
                    "fields": {
                        "keyword": {
                            "type": "keyword",
                            "ignore_above": 256
                        }
                    }
                }
            }
        },
        "settings": {
            "index": {
                "creation_date": "1585832833661",
                "number_of_shards": "1",
                "number_of_replicas": "1",
                "uuid": "xxxxxx",
                "version": {
                    "created": "xxxxx"
                },
                "provided_name": "idx5"
            }
        }
    }
}

感谢您的帮助

尝试改用此查询,即使用 element_type.keyword 而不是 element_type:

$query = '{
    "query": {
        "bool": {
            "must_not": {
                "term" : { "element_type.keyword" : "TYPE1" }      <----- change here
            },
            "should": [
                {
                    "match_phrase": {
                        "title": {
                            "query": "test"
                        }
                    }
                }
            ]
        }
    }
}';

对此的解释如下:当您没有为字符串字段指定映射时,它们将使用 text 类型和 keyword 子字段创建。

因此,当在您的 element_type 字段中索引值 TEST1 时:

  • test1 将在 element_type 字段中建立索引(文本字段默认由 standard analyzer 分析)
  • TEST1 将在 element_type.keyword 子字段中编入索引(keyword fields 未按原样分析和编入索引)

知道了这一点,您就可以用两种不同的方式制作 must_not 查询。

element_type 字段上使用 match 查询:

"match" : { "element_type" : "type1" }

或在 element-type.keyword 子字段上使用 term 查询(具有精确值匹配)

"term" : { "element_type.keyword" : "TYPE1" }

如果你真的想用 term 查询来查询 element_type 字段,那么你需要将你的值小写,就像这样(即你想对分析的值进行精确匹配):

"term" : { "element_type" : "type1" }