Kombinacja zapytań bool elastsearch musi mieć wartość OR


181

Obecnie próbuję przeprowadzić migrację aplikacji opartej na SOLR do Elasticsearch.

Mam to zapytanie lucene

(( 
    name:(+foo +bar) 
    OR info:(+foo +bar) 
)) AND state:(1) AND (has_image:(0) OR has_image:(1)^100)

O ile rozumiem, jest to kombinacja klauzul MUST połączonych z logiczną OR:

„Pobierz wszystkie dokumenty zawierające (foo AND bar w nazwie) OR (foo AND bar w info). Następnie filtruj wyniki według stanu warunku = 1 i popraw dokumenty, które mają obraz.”

Próbowałem użyć zapytania bool z MUST, ale nie udało mi się uzyskać logicznych klauzul OR w klauzulach must. Oto co mam:

GET /test/object/_search
{
  "from": 0,
  "size": 20,
  "sort": {
    "_score": "desc"
  },
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "foo"
          }
        },
        {
          "match": {
            "name": "bar"
          }
        }
      ],
      "must_not": [],
      "should": [
        {
          "match": {
            "has_image": {
              "query": 1,
              "boost": 100
            }
          }
        }
      ]
    }
  }
}

Jak widać, MUSI brakować warunków dla „informacji”.

Czy ktoś ma rozwiązanie?

Dziękuję bardzo.

** AKTUALIZACJA **

Zaktualizowałem zapytanie elastyczne i pozbyłem się wyniku funkcji. Mój podstawowy problem nadal istnieje.


1
Jest dokumentacja dobre na łączenie ElasticSearch zapytań tutaj: elastic.co/guide/en/elasticsearch/guide/current/...
Mr.Coffee

Odpowiedzi:


426
  • OR jest napisane powinno
  • ORAZ jest zapisany jako musi
  • NOR jest zapisywane jako powinno_nie

Przykład:

Chcesz zobaczyć wszystkie elementy, które są (okrągłe ORAZ (czerwony LUB niebieski)):

{
    "query": {
        "bool": {
            "must": [
                {
                    "term": {"shape": "round"}
                },
                {
                    "bool": {
                        "should": [
                            {"term": {"color": "red"}},
                            {"term": {"color": "blue"}}
                        ]
                    }
                }
            ]
        }
    }
}

Możesz także wykonać bardziej złożone wersje OR, na przykład jeśli chcesz dopasować co najmniej 3 z 5, możesz określić 5 opcji w „powinno” i ustawić „minimum_should” na 3.

Dziękuję Glenowi Thompsonowi i Sebastialonso za odkrycie, gdzie wcześniej moje zagnieżdżenie nie było takie dobre.

Dziękuję również Fatmajkowi za wskazanie, że „termin” staje się „dopasowaniem” w ElasticSearch 6.


2
Czy wciągnięcie shouldna wyższy poziom booli włączenie minimum_should_match: 1pracy?
Sid

18
Kiedy próbuję tego przykładu, wracam [term] malformed query, expected [END_OBJECT] but found [FIELD_NAME]. Czy to w jakiś sposób zależy od wersji?
DanneJ

26
Dlaczego nie dodają tak prostego przykładu i wyjaśnienia w dokumentacji! Przykład z dokumentacji jest bardzo zagmatwany.
Nikhil Owalekar

21
Po 6 miesiącach, czytając całą dokumentację Elastic, po raz pierwszy w pełni rozumiem, jak zaimplementować logikę boolowską. Moim zdaniem oficjalna dokumentacja jest niejasna.
Sebastialonso

3
@Amir Jakie nieścisłości mogę dla Ciebie usunąć? W kontekście pokazanym powyżej wartością domyślną minimum_shouldjest 1, a zawijanie boolpowoduje, że ta grupa jest prawdziwa, jeśli co najmniej jeden element pasuje, lub fałsz, jeśli żaden nie pasuje. Moją motywacją do stworzenia tej odpowiedzi było to, że rozwiązałem dokładnie tego rodzaju problem, a dostępna dokumentacja, a nawet odpowiedzi, które mogłem znaleźć na takich stronach, były w najlepszym razie nieprzydatne, więc szukałem dalej, dopóki nie poczułem, że mam dość solidną wiedzę tego, co się działo. Z radością przyjmuję wszelkie konstruktywne wskazówki, w jaki sposób mogę ulepszyć odpowiedź.
Daniel Fackrell,

69

W końcu udało mi się stworzyć zapytanie, które robi dokładnie to, co chciałem:

Filtrowane zagnieżdżone zapytanie logiczne. Nie jestem pewien, dlaczego nie jest to udokumentowane. Może ktoś tutaj może mi powiedzieć?

Oto zapytanie:

GET /test/object/_search
{
  "from": 0,
  "size": 20,
  "sort": {
    "_score": "desc"
  },
  "query": {
    "filtered": {
      "filter": {
        "bool": {
          "must": [
            {
              "term": {
                "state": 1
              }
            }
          ]
        }
      },
      "query": {
        "bool": {
          "should": [
            {
              "bool": {
                "must": [
                  {
                    "match": {
                      "name": "foo"
                    }
                  },
                  {
                    "match": {
                      "name": "bar"
                    }
                  }
                ],
                "should": [
                  {
                    "match": {
                      "has_image": {
                        "query": 1,
                        "boost": 100
                      }
                    }
                  }
                ]
              }
            },
            {
              "bool": {
                "must": [
                  {
                    "match": {
                      "info": "foo"
                    }
                  },
                  {
                    "match": {
                      "info": "bar"
                    }
                  }
                ],
                "should": [
                  {
                    "match": {
                      "has_image": {
                        "query": 1,
                        "boost": 100
                      }
                    }
                  }
                ]
              }
            }
          ],
          "minimum_should_match": 1
        }
      }    
    }
  }
}

W pseudo-SQL:

SELECT * FROM /test/object
WHERE 
    ((name=foo AND name=bar) OR (info=foo AND info=bar))
AND state=1

Należy pamiętać, że to, jak nazwa = foo jest wewnętrznie obsługiwana, zależy od analizy pól dokumentu i mapowań. Może się to różnić od rozmytego do ścisłego zachowania.

„minimum_should_match”: 1 mówi, że przynajmniej jedna z instrukcji powinna być prawdziwa.

To stwierdzenie oznacza, że ​​ilekroć w zestawie wyników znajduje się dokument, który zawiera has_image: 1, jest on zwiększany o współczynnik 100. To zmienia kolejność wyników.

"should": [
  {
    "match": {
      "has_image": {
        "query": 1,
        "boost": 100
      }
    }
   }
 ]

Bawcie się dobrze :)


28
O kurczę. Czy ktoś ma lepsze rozwiązanie? Dziękuję za opublikowanie tego, ale jest to zdecydowanie zbyt duża złożoność, aby uzyskać logiczne LUB w zapytaniu.
nackjicholson

thnx, uratowałeś mi dzień)
cubbiu

3
To zapytanie jest nie tylko niepotrzebnie długie, ale używa przestarzałej składni. Odpowiedź @ daniel-fackrell powinna być zaakceptowana.
Eric Alford

4
@EricAlford Ta odpowiedź z 2015 roku jest oparta na wcześniejszej wersji ES. Zapraszam do zapewnienia lepszego rozwiązania.
Jesse

1
Pomysł: Przejmij / rozwidlaj ElasticSearch, przepisz go w przyjazny dla użytkownika sposób, dodaj do niego prosty język zapytań, WYGRAJ! Potrzebujemy tylko finansowania. Jestem za! Kto jeszcze ?
Sliq

16

W ten sposób możesz zagnieżdżać wiele zapytań bool w jednym zewnętrznym zapytaniu bool za pomocą Kibana,

bool wskazuje, że używamy wartości logicznej

musi jest dla AND

powinno być dla OR

GET my_inedx/my_type/_search
{
    "query" : {
       "bool": {             //bool indicates we are using boolean operator
            "must" : [       //must is for **AND**
                 {
                   "match" : {
                         "description" : "some text"  
                     }
                 },
                 {
                    "match" :{
                          "type" : "some Type"
                     }
                 },
                 {
                    "bool" : {          //here its a nested boolean query
                          "should" : [  //should is for **OR**
                                 {
                                   "match" : {
                                       //ur query
                                  }
                                 },
                                 { 
                                    "match" : {} 
                                 }     
                               ]
                          }
                 }
             ]
        }
    }
}

W ten sposób można zagnieździć zapytanie w ES

W „bool” jest więcej typów, na przykład -

  1. Filtr

  2. nie możesz


Twoja odpowiedź jest dokładnie poprawna, ale jest trochę niezdarna, to mała sugestia, jeśli chcesz - musisz ją odpowiednio edytować. Zapewne da ci to więcej polubienia w tej odpowiedzi :) Miłego dnia.
Dhwanil Patel

6

Niedawno też musiałem rozwiązać ten problem i po wielu próbach i błędach wymyśliłem to (w PHP, ale mapuje bezpośrednio na DSL):

'query' => [
    'bool' => [
        'should' => [
            ['prefix' => ['name_first' => $query]],
            ['prefix' => ['name_last' => $query]],
            ['prefix' => ['phone' => $query]],
            ['prefix' => ['email' => $query]],
            [
                'multi_match' => [
                    'query' => $query,
                    'type' => 'cross_fields',
                    'operator' => 'and',
                    'fields' => ['name_first', 'name_last']
                ]
            ]
        ],
        'minimum_should_match' => 1,
        'filter' => [
            ['term' => ['state' => 'active']],
            ['term' => ['company_id' => $companyId]]
        ]
    ]
]

Który mapuje na coś takiego w SQL:

SELECT * from <index> 
WHERE (
    name_first LIKE '<query>%' OR
    name_last LIKE '<query>%' OR
    phone LIKE  '<query>%' OR
    email LIKE '<query>%'
)
AND state = 'active'
AND company_id = <query>

Kluczem w tym wszystkim jest minimum_should_matchustawienie. Bez tego filtercałkowicie zastępuje should.

Mam nadzieję, że to komuś pomoże!


0
$filterQuery = $this->queryFactory->create(QueryInterface::TYPE_BOOL, ['must' => $queries,'should'=>$queriesGeo]);

W mustmusisz dodać tablicę warunków zapytania, z którą chcesz pracować, ANDaw niej shouldmusisz dodać warunek zapytania, z którym chcesz pracować OR.

Możesz to sprawdzić: https://github.com/Smile-SA/elasticsuite/issues/972


0

Jeśli używasz domyślnego parsera zapytań Solr lub Lucene, prawie zawsze możesz umieścić go w zapytaniu w postaci ciągu zapytania:

POST test/_search
{
  "query": {
    "query_string": {
      "query": "(( name:(+foo +bar) OR info:(+foo +bar)  )) AND state:(1) AND (has_image:(0) OR has_image:(1)^100)"
    }
  }
}

To powiedziawszy, możesz chcieć użyć zapytania logicznego , takiego jak to, które już opublikowałeś, lub nawet kombinacji tych dwóch.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.