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.

Jesse
źródło
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.

Daniel Fackrell
źródło
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 :)

Jesse
źródło
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

niranjan harpale
źródło
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!

Benjamin Dowson
źródło
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

alakh kumar
źródło
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.

Radu Gheorghe
źródło