elasticsearch bool แบบสอบถามต้องรวมกับ OR


181

ขณะนี้ฉันกำลังพยายามโยกย้ายแอปพลิเคชันที่ใช้ solr ไปยัง ElasticSearch

ฉันมีคำถามลูซีนนี้

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

เท่าที่ฉันเข้าใจนี่คือการรวมกันของข้อต้องรวมกับบูลีนหรือ:

"รับเอกสารทั้งหมดที่มี (foo AND bar ในชื่อ) หรือ (foo AND bar in info) หลังจากนั้นกรองผลลัพธ์ตามเงื่อนไข state = 1 และเพิ่มเอกสารที่มีรูปภาพ"

ฉันพยายามใช้คำสั่งบูลด้วยต้อง แต่ฉันไม่สามารถรับบูลีนหรือต้องมีคำสั่ง นี่คือสิ่งที่ฉันมี:

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
            }
          }
        }
      ]
    }
  }
}

อย่างที่คุณเห็นต้องไม่มีเงื่อนไขสำหรับ "ข้อมูล"

ไม่มีใครมีทางออกหรือไม่?

ขอบคุณมาก.

** อัพเดท **

ฉันได้อัปเดตการสืบค้น ElasticSearch แล้วและลบคะแนนฟังก์ชันนั้น ปัญหาพื้นฐานของฉันยังคงมีอยู่


1
มีเอกสารที่ดีเกี่ยวกับการรวมการสืบค้น ElasticSearch ที่นี่: elastic.co/guide/en/elasticsearch/guide/current/ ......
Mr.Coffee

คำตอบ:


426
  • หรือถูกสะกดควร
  • และจะต้องสะกด
  • NORสะกดถูกต้องไม่ควร

ตัวอย่าง:

คุณต้องการที่จะเห็นรายการทั้งหมดที่เป็น (รอบและ (สีแดงหรือสีน้ำเงิน)):

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

นอกจากนี้คุณยังสามารถทำ OR เวอร์ชันที่ซับซ้อนมากขึ้นเช่นถ้าคุณต้องการจับคู่อย่างน้อย 3 จาก 5 คุณสามารถระบุ 5 ตัวเลือกภายใต้ "ควร" และตั้ง "ขั้นต่ำ" ควรเป็น 3

ขอบคุณ Glen Thompson และ Sebastialonso ที่หารังของฉันไม่ถูกต้องมาก่อน

ขอบคุณ Fatmajk ที่ชี้ให้เห็นว่า "คำว่า" กลายเป็น "การจับคู่" ใน ElasticSearch 6


2
จะดึงshouldเข้าไปในระดับบนboolและรวมถึงการminimum_should_match: 1ทำงานหรือไม่
ซิด

18
[term] malformed query, expected [END_OBJECT] but found [FIELD_NAME]เมื่อฉันพยายามตัวอย่างนี้ผมได้รับกลับมา รุ่นนี้ขึ้นอยู่กับอะไร
DanneJ

26
ทำไมพวกเขาไม่เพิ่มตัวอย่างง่ายๆและคำอธิบายลงในเอกสาร! ตัวอย่างจากเอกสารมีความสับสนมาก
Nikhil Owalekar

21
หลังจาก 6 เดือน, อ่านเอกสาร Elastic ทั้งหมด, นี่เป็นครั้งแรกที่ฉันเข้าใจวิธีใช้ตรรกะบูลีนอย่างสมบูรณ์ เอกสารทางการไม่มีความชัดเจนในความคิดของฉัน
Sebastialonso

3
@Amir ฉันสามารถทำความสะอาดอะไรให้คุณบ้าง ในบริบทที่แสดงด้านบนค่าเริ่มต้นminimum_shouldคือ 1 และการตัดคำในboolผลลัพธ์ในกลุ่มนั้นจะเป็นจริงถ้ามีอย่างน้อยหนึ่งรายการที่ตรงกันเป็นเท็จถ้าไม่มีข้อมูลตรงกัน แรงจูงใจของฉันในการสร้างคำตอบนี้คือฉันได้แก้ไขปัญหาแบบนี้อย่างแน่นอนและเอกสารที่มีอยู่และแม้กระทั่งคำตอบที่ฉันสามารถหาได้ในเว็บไซต์เช่นนี้ก็ไม่ได้ช่วยเหลืออะไรดีที่สุดดังนั้นฉันจึงทำการค้นคว้าต่อไปจนกระทั่งฉันรู้สึกว่า ของสิ่งที่เกิดขึ้น ฉันยินดีต้อนรับพอยน์เตอร์ที่สร้างสรรค์เกี่ยวกับวิธีที่ฉันสามารถปรับปรุงคำตอบเพิ่มเติมได้
Daniel Fackrell

69

ในที่สุดฉันก็สามารถสร้างแบบสอบถามที่ทำสิ่งที่ฉันต้องการได้:

แบบสอบถามบูลีนที่ซ้อนกันที่กรองแล้ว ฉันไม่แน่ใจว่าทำไมไม่มีเอกสารนี้ บางทีใครบางคนที่นี่สามารถบอกฉันได้?

นี่คือแบบสอบถาม:

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

ในหลอก SQL:

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

โปรดทราบว่าขึ้นอยู่กับการวิเคราะห์ฟิลด์เอกสารของคุณและการแมปว่า name = foo มีการจัดการภายในอย่างไร สิ่งนี้อาจแตกต่างจากความคลุมเครือไปจนถึงพฤติกรรมที่เข้มงวด

"Minimum_should_match": 1 บอกว่าอย่างน้อยหนึ่งในข้อความสั่งควรจะต้องเป็นจริง

คำสั่งนี้หมายความว่าเมื่อใดก็ตามที่มีเอกสารใน resultset ที่มี has_image: 1 จะได้รับการส่งเสริมโดยปัจจัย 100 การเปลี่ยนแปลงนี้ทำให้เกิดการเรียงลำดับผลลัพธ์

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

ขอให้สนุกกับพวก :)


28
อึศักดิ์สิทธิ์ ไม่มีใครมีทางออกที่ดีกว่า? ขอบคุณสำหรับการโพสต์สิ่งนี้ แต่นั่นเป็นวิธีที่ซับซ้อนมากเกินไปที่จะบรรลุ Logical OR ในแบบสอบถาม
nackjicholson

ขอบคุณคุณบันทึกวันของฉัน)
cubbiu

3
แบบสอบถามนี้ไม่เพียง แต่จะมีความยาวโดยไม่จำเป็นเท่านั้น แต่ยังมีการใช้ไวยากรณ์ที่เลิกใช้แล้ว @ daniel-fackrell คำตอบควรเป็นคำตอบที่ยอมรับได้
Eric Alford

4
@EricAlford คำตอบนี้จากปี 2558 อิงจาก ES รุ่นก่อนหน้า อย่าลังเลที่จะมอบทางออกที่ดีกว่า
เจสซี่

1
ความคิด: ใช้เวลานานกว่า / แยก ElasticSearch เขียนใหม่ด้วยวิธีที่ใช้งานง่ายเพิ่มภาษาข้อความค้นหาอย่างง่ายชนะ! เราแค่ต้องการเงินทุน ฉันอยู่ใน! มีใครอีกบ้าง?
Sliq

16

นี่คือวิธีที่คุณสามารถซ้อนเคียวรีบูลหลายรายการในเคียวรีบูลภายนอกหนึ่งรายการโดยใช้ Kibana

บูลบ่งบอกว่าเรากำลังใช้บูลีน

ต้องเป็นสำหรับและ

ควรสำหรับหรือ

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

นี่คือวิธีที่คุณสามารถซ้อนเคียวรีใน ES

มีหลายประเภทใน "บูล" เช่น -

  1. กรอง

  2. ต้องไม่


คำตอบของคุณถูกต้อง แต่มันค่อนข้างงุ่มง่ามมันเป็นคำแนะนำเล็กน้อยสำหรับคุณถ้าคุณต้องการคุณต้องแก้ไขให้ถูกต้อง อาจจะให้คำตอบกับคุณมากกว่านี้ :) ขอให้มีความสุขมาก ๆ ในวันนี้นะ
Dhwanil Patel

6

ฉันเพิ่งต้องแก้ปัญหานี้เช่นกันและหลังจากการทดลองและข้อผิดพลาดมากมายฉันพบสิ่งนี้ (ใน PHP แต่แมปโดยตรงกับ 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]]
        ]
    ]
]

แมปอะไรกับสิ่งนี้ใน 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>

กุญแจสำคัญในทั้งหมดนี้คือการminimum_should_matchตั้งค่า โดยไม่ต้องนี้filterโดยสิ้นเชิงแทนที่shouldโดยสิ้นเชิงแทนที่

หวังว่านี่จะช่วยใครซักคน!


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

ในmustคุณจำเป็นต้องเพิ่มอาร์เรย์เงื่อนไขการค้นหาที่คุณต้องการที่จะทำงานร่วมกับANDและคุณจำเป็นต้องเพิ่มเงื่อนไขการค้นหาที่คุณต้องการที่จะทำงานร่วมกับshouldOR

คุณสามารถตรวจสอบได้ที่: https://github.com/Smile-SA/elasticsuite/issues/972


0

หากคุณใช้ตัวแยกวิเคราะห์เริ่มต้นของ Lucr หรือตัวแยกวิเคราะห์แบบสอบถาม Lucene คุณสามารถใส่ลงในแบบสอบถามสตริงแบบสอบถามได้เสมอ:

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

ที่กล่าวว่าคุณอาจต้องการใช้แบบสอบถามบูลีนเช่นเดียวกับที่คุณโพสต์แล้วหรือแม้กระทั่งการรวมกันของทั้งสอง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.