Неоправданно условие по смыслу эластичного поиска must_not не работает - PullRequest
0 голосов
/ 02 апреля 2020

Посмотрите на этот запросasticsearch:

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

Я работаю с 6.2.4 версией elasti c search.

Все работало нормально, но в последние дни я получаю результаты с Значения TYPE1, TYPE2, TYPE3 в поле element_type.

Ничего не изменилось ...

Есть ли у вас какие-либо идеи о проблеме?

Спасибо

* РЕДАКТИРОВАТЬ *

Я создал скрипт php, который демонстрирует проблему. Я запустил его на fre sh elasti c search install:

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

Спасибо за вашу помощь

1 Ответ

0 голосов
/ 02 апреля 2020

Попробуйте использовать этот запрос вместо этого, то есть с 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.

Поэтому при индексации значения TEST1 в вашем поле element_type:

  • test1 будет проиндексирован в поле element_type (текстовые поля анализируются стандартным анализатором * по умолчанию 1018 *)
  • 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, то вам нужно указать строчную букву вашего значения, например (например, вы хотите точно сопоставить анальный значение yzed):

"term" : { "element_type" : "type1" }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...