首页 > 解决方案 > elasticsearch must_not terms 子句不起作用

问题描述

看看这个弹性搜索查询:

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

谢谢你的帮助

标签: elasticsearchelasticsearch-query

解决方案


尝试改用此查询,即使用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子字段创建。

因此,在索引字段中的值TEST1element_type

  • test1将在element_type字段中被索引(文本字段默认由标准分析器分析
  • TEST1将在element_type.keyword子字段中进行索引(关键字字段不按原样分析和索引)

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

要么match在字段上进行查询element_type

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

或对子字段进行term查询(具有精确值匹配)element-type.keyword

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

如果您真的想通过查询来查询该element_type字段term,那么您需要将您的值小写,如下所示(即您想对分析的值进行完全匹配):

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

推荐阅读