ตัวกรอง

ด้วย Qdrant คุณสามารถกำหนดเงื่อนไขสำหรับการค้นหาหรือการเรียกรับจุด ซึ่งหมายความว่าคุณสามารถกรองตามแอตทริบิวต์นอกเหนือจากการค้นหาความคล้ายคลึงสำหรับเวกเตอร์ คล้ายกับการกำหนดเงื่อนไข SQL where ตัวอย่างเช่น คุณสามารถกำหนดเงื่อนไขสำหรับพล็อตที่ payload และ id

สำคัญที่จะกำหนดเงื่อนไขเพิ่มเติมเมื่อไม่สามารถแสดงถึงคุณสมบัติของวัตถุทั้งหมดได้ในการฝังเข็ม เช่น ความต้องการทางธุรกิจต่าง ๆ เช่น ความพร้อมในสต็อก ที่ตั้งของผู้ใช้ หรือช่วงราคาที่คาดหวัง

เงื่อนไขตัวกรอง

Qdrant อนุญาตให้คุณรวมเงื่อนไขในคลอส คลอสเป็นการดำเนินการตรรกะทางตรรกะคล้ายกับ OR, AND, และ NOT คลอสสามารถถูกซ้อนกันแบบแบบที่ต่างกัน เพื่อนำกลับมาให้อยู่ในนิพจน์บูลีนที่แตกต่างได้

มาดูวิธีการใช้คลอสที่ถูกนำมาใช้ใน Qdrant กัน

สมมติว่าเรามีชุดของพล็อตพร้อมด้วย payload:

[
  { "id": 1, "city": "London", "color": "green" },
  { "id": 2, "city": "London", "color": "red" },
  { "id": 3, "city": "London", "color": "blue" },
  { "id": 4, "city": "Berlin", "color": "red" },
  { "id": 5, "city": "Moscow", "color": "green" },
  { "id": 6, "city": "Moscow", "color": "blue" }
]

จะต้อง

ตัวอย่าง:

POST /collections/{collection_name}/points/scroll

{
    "filter": {
        "must": [
            { "key": "city", "match": { "value": "London" } },
            { "key": "color", "match": { "value": "red" } }
        ]
    }
  ...
}

จุดที่ผ่านการกรองคือ:

[{ "id": 2, "city": "London", "color": "red" }]

เมื่อใช้ must, คลอสจะเป็น true เฉพาะเมื่อทุกเงื่อนไขที่ระบุใน must ถูกทำอย่างเต็มที่ ในทางนี้ must เทียบเท่ากับตัวดำเนินการ AND

ควร

ควร คล้ายกับตัวดำเนินการ OR ใน SQL

ตัวอย่าง:

POST /collections/{collection_name}/points/scroll

{
    "filter": {
        "should": [
            { "key": "city", "match": { "value": "London" } },
            { "key": "color", "match": { "value": "red" } }
        ]
    }
  ...
}

จุดที่ผ่านการกรองคือ:

[
  { "id": 1, "city": "London", "color": "green" },
  { "id": 2, "city": "London", "color": "red" },
  { "id": 3, "city": "London", "color": "blue" },
  { "id": 4, "city": "Berlin", "color": "red" }
]

เมื่อใช้ should, คลอสจะเป็น true ตลอดเวลาเมื่ออย่างน้อยหนึ่งเงื่อนไขที่ระบุใน should ถูกทำอย่างเต็มที่ ในทางนี้ should เทียบเท่ากับตัวดำเนินการ OR

ต้องไม่

ตัวอย่าง:

POST /collections/{collection_name}/points/scroll

{
    "filter": {
        "must_not": [
            { "key": "city", "match": { "value": "London" } },
            { "key": "color", "match": { "value": "red" } }
        ]
    }
  ...
}

จุดที่ผ่านการกรองคือ:

[
  { "id": 5, "city": "Moscow", "color": "green" },
  { "id": 6, "city": "Moscow", "color": "blue" }
]

เมื่อใช้ must_not, คลอสย่อยจะเป็น true เฉพาะเมื่อไม่มีเงื่อนไขที่ระบุใน must_not ถูกทำอย่างเต็มที่ ในทางนี้ must_not เทียบเท่ากับนิพจน์ (NOT A) AND (NOT B) AND (NOT C)

การผสานเงื่อนไข

ใช้เงื่อนไขหลายรายการพร้อมกันได้:

POST /collections/{collection_name}/points/scroll

{
    "filter": {
        "must": [
            { "key": "city", "match": { "value": "London" } }
        ],
        "must_not": [
            { "key": "color", "match": { "value": "red" } }
        ]
    }
  ...
}

จุดที่ได้กรองแล้วจะเป็นดังนี้:

[
  { "id": 1, "city": "London", "color": "green" },
  { "id": 3, "city": "London", "color": "blue" }
]

ในกรณีนี้เงื่อนไขถูกผสานด้วย AND.

นอกจากนี้ เงื่อนไขสามารถถูกซ้อนกันได้โดยเรียกตัวเองอีกครั้ง เช่น:

POST /collections/{collection_name}/points/scroll

{
    "filter": {
        "must_not": [
            {
                "must": [
                    { "key": "city", "match": { "value": "London" } },
                    { "key": "color", "match": { "value": "red" } }
                ]
            }
        ]
    }
  ...
}

จุดที่กรองแล้วจะเป็นดังนี้:

[
  { "id": 1, "city": "London", "color": "green" },
  { "id": 3, "city": "London", "color": "blue" },
  { "id": 4, "city": "Berlin", "color": "red" },
  { "id": 5, "city": "Moscow", "color": "green" },
  { "id": 6, "city": "Moscow", "color": "blue" }
]

การกรองเงื่อนไข

ในข้อมูลส่ง, ค่าประเภทต่างๆที่ประกอบด้วยชนิดของการค้นหาที่สามารถนำไปปรับใช้ได้. ขอดูตัวอย่างเงื่อนไขต่างๆและชนิดข้อมูลที่มันนำไปใช้

การจับคู่

{
  "key": "color",
  "match": {
    "value": "red"
  }
}

สำหรับชนิดอื่นๆ เงื่อนไขการจับคู่ดูเหมือนกันทุกประการ แค่เพียงแต่ใช้ชนิดที่ต่างกัน:

{
  "key": "count",
  "match": {
    "value": 0
  }
}

การตรวจสอบเงื่อนไขที่ง่ายที่สุดคือการตรวจสอบว่าค่าที่จัดเก็บเท่ากับค่าที่กำหนด. หากมีการจัดเก็บค่าหลายค่า อย่างน้อยหนึ่งค่าต้องเป็นไปตามเงื่อนไข. นี้สามารถนำไปปรับใช้กับ payload ช่องคำสำคัญ, ตัวเลข, และค่าบูลีน

การจับคู่ใดๆ

ใช้ได้ตั้งแต่ v1.1.0

หากต้องการตรวจสอบว่าค่าที่จัดเก็บเป็นหนึ่งในค่าหลายๆค่า คุณสามารถใช้การจับคู่ใดๆ. การจับคู่ใดๆจะจับคู่ค่าที่กำหนดเป็นการดำเนินการ OR ตรรกะ. มันยังสามารถอธิบายได้ว่าเป็นตัวดำเนินการ IN

คุณสามารถนำไปปรับใช้กับ payload ชุดคำสำคัญ และ เลขจำนวนเต็ม

ตัวอย่าง:

{
  "key": "color",
  "match": {
    "any": ["black", "yellow"]
  }
}

ในตัวอย่างนี้ หากค่าที่จัดเก็บเป็น black หรือ yellow แล้วเงื่อนไขจะถูกพอใจ

หากค่าที่จัดเก็บเป็นอาร์เรย์, จะต้องมีอย่างน้อยหนึ่งค่าที่ตรงกับค่าที่กำหนด ยกตัวอย่างเช่น หากค่าที่จัดเก็บเป็น ["black", "green"], แล้วเงื่อนไขจะถูกพอใจเพราะ "black" อยู่ใน ["black", "yellow"].

การจับคู่ที่ยกเว้น

ใช้ได้ตั้งแต่ v1.2.0

หากต้องการตรวจสอบว่าค่าที่ถูกจัดเก็บไม่ใช่หนึ่งในค่าหลายๆค่า คุณสามารถใช้การจับคู่ที่ยกเว้น. การจับคู่ที่ยกเว้นจะจับคู่ค่าที่กำหนดเป็นการดำเนินการ NOR ตรรกะ. มันยังสามารถอธิบายได้ว่าเป็นตัวดำเนินการ NOT IN

คุณสามารถนำไปปรับใช้กับ payload ชุดคำสำคัญ และ เลขจำนวนเต็ม

ตัวอย่าง:

{
  "key": "color",
  "match": {
    "except": ["black", "yellow"]
  }
}

ในตัวอย่างนี้ หากค่าที่ถูกจัดเก็บไม่ใช่ black และไม่ใช่ yellow แล้วเงื่อนไขจะถูกพอใจ

หากค่าที่ถูกจัดเก็บเป็นอาร์เรย์, จะต้องมีค่าที่อย่างน้อยหนึ่งค่าที่ไม่ตรงกับค่าที่กำหนด ยกตัวอย่างเช่น, หากค่าที่ถูกจัดเก็บเป็น ["black", "green"], แล้วเงื่อนไขจะถูกพอใจเพราะ "green" ไม่ตรงกับ "black" หรือ "yellow".

คีย์ที่ซ้อนกัน

สามารถใช้ได้ตั้งแต่ v1.1.0 เป็นต้นไป

เนื่องจากข้อมูลส่งออกเป็นออบเจ็กต์ JSON ที่อรรถรสได้เราอาจต้องกรองฟิลด์ที่ซ้อนกัน

เพื่อความสะดวก เราใช้ไวยากรณ์ที่คล้ายกับโปรเจกต์ Jq

สมมติว่าเรามีชุดของจุดพร้อมกับข้อมูลดังต่อไปนี้:

[
  {
    "id": 1,
    "country": {
      "name": "เยอรมนี",
      "cities": [
        {
          "name": "เบอร์ลิน",
          "population": 3.7,
          "sightseeing": ["ประตูบร็อง]นบุรันสด", "ไรช์สตาก"]
        },
        {
          "name": "มิวนิค",
          "population": 1.5,
          "sightseeing": ["มารีเอนพลาตซ์", "ปาร์กออลิมปิค"]
        }
      ]
    }
  },
  {
    "id": 2,
    "country": {
      "name": "ญี่ปุ่น",
      "cities": [
        {
          "name": "โตเกียว",
          "population": 9.3,
          "sightseeing": ["โตเกียวทาวเวอร์", "ทรีท็อกี้สกายทรี"]
        },
        {
          "name": "โอซาก้า",
          "population": 2.7,
          "sightseeing": ["ปราสาทโอซาก้า", "ยูนิเวอร์ซัลสตูดิโอส ญี่ปุ่น"]
        }
      ]
    }
  }
]

คุณสามารถใช้จำนองด็อทเพื่อค้นหาฟิลด์ที่ซ้อนกัน

POST /collections/{collection_name}/points/scroll

{
    "filter": {
        "should": [
            {
                "key": "country.name",
                "match": {
                    "value": "เยอรมนี"
                }
            }
        ]
    }
}

คุณยังสามารถใช้ไวยากรณ์ [ ] เพื่อค้นหาอาร์เรย์โดยการสร้างค่าภายใน

POST /collections/{collection_name}/points/scroll

{
    "filter": {
        "should": [
            {
                "key": "country.cities[].population",
                "range": {
                    "gte": 9.0,
                }
            }
        ]
    }
}

คิวรี่นี้จะแสดงเฉพาะจุดที่มี id คือ 2 เนื่องจากเฉพาะประเทศญี่ปุ่นมีเมืองที่มีประชากรมากกว่า 9.0

ฟิลด์ที่ซ้อนกันยังอาจเป็นอาร์เรย์

POST /collections/{collection_name}/points/scroll

{
    "filter": {
        "should": [
            {
                "key": "country.cities[].sightseeing",
                "match": {
                    "value": "ปราสาทโอซาก้า"
                }
            }
        ]
    }
}

คิวรี่นี้จะแสดงเฉพาะจุดที่มี id คือ 2 เนื่องจากเมืองประเทศญี่ปุ่นมีสถานท่องเที่ยวที่รวม "ปราสาทโอซาก้า" อยู่

การกรองอ็อบเจกต์ที่ซ้อนกัน

มีให้ใช้ตั้งแต่เวอร์ชัน 1.2.0

ตามค่าเริ่มต้นเงื่อนไขจะพิจารณาข้อมูลทั้งหมดของพอยต์

ตัวอย่างเช่น จากพอยต์ทั้งสองในข้อมูลด้านล่าง:

[
  {
    "id": 1,
    "dinosaur": "t-rex",
    "diet": [
      { "food": "leaves", "likes": false},
      { "food": "meat", "likes": true}
    ]
  },
  {
    "id": 2,
    "dinosaur": "diplodocus",
    "diet": [
      { "food": "leaves", "likes": true},
      { "food": "meat", "likes": false}
    ]
  }
]

คิวรีต่อไปนี้จะตรงกับพอยต์ทั้งสองเหล่านี้:

POST /collections/{collection_name}/points/scroll

{
    "filter": {
        "must": [
            {
                "key": "diet[].food",
                  "match": {
                    "value": "meat"
                }
            },
            {
                "key": "diet[].likes",
                  "match": {
                    "value": true
                }
            }
        ]
    }
}

เหตุผลที่พอยต์ทั้งสองข้างต้นตรงกันคือเพราะทั้งสองจุดมีเงื่อนไขเหล่านี้ทุกอย่างนี้เข้าท่าเทียบ:

  • "t-rex" ตรงกับ diet[1].food พร้อมอาหาร = เนื้อ และ diet[1].likes กับ likes = true
  • "diplodocus" ตรงกับ diet[1].food พร้อมอาหาร = เนื้อ และ diet[0].likes กับ likes = true

หากต้องการรับเพียงพอยต์ที่ตรงกับเงื่อนไขสำหรับอาร์เรย์องค์ประกอบ ตัวอย่างเช่น พอยต์ที่มี id 1 ในตัวอย่างนี้ คุณต้องใช้ตัวกรองอ็อบเจกต์ที่ซ้อนกัน

ตัวกรองอ็อบเจกต์ที่ซ้อนกันช่วยให้คุณสามารถสอบถามอาร์เรย์ออบเจกต์โดยอิสระ

นี้สามารถทำได้โดยใช้ประเภทเงื่อนไข nested ซึ่งประกอบด้วยคีย์เพย์ของพอยต์ที่สนใจและตัวกรองที่จะใช้

คีย์ควรชี้ไปที่อาร์เรย์ออบเจกต์ และสามารถใช้สัญลักษณ์วงเล็บตามต้องการ ("data" หรือ "data[]")

POST /collections/{collection_name}/points/scroll

{
    "filter": {
        "must": [
            "nested": {
                {
                    "key": "diet",
                    "filter": {
                        "must": [
                            {
                                "key": "food",
                                "match": {
                                    "value": "meat"
                                }
                            },
                            {
                                "key": "likes",
                                "match": {
                                    "value": true
                                }
                            }
                        ]
                    }
                }
            }
        ]
    }
}

ตรรกสูตรการตรงกันถูกแก้ไขเพื่อใช้กับระดับอาร์เรย์องค์ประกอบภายในพอยต์

ตัวกรองอ็อบเจกต์ที่ซ้อนกันทำงานเหมือนกับเมื่อนำตัวกรองอ็อบเจกต์ที่ซ้อนกันไปใช้กับองค์ประกอบเดี่ยว แค่แม้กรองที่ซ้อนเป็นกันอย่างน้อยหนึ่งองค์ พอยต์แม่ก็ถือว่าตรงกับเงื่อนไข

ข้อจำกัด

ตัวกรองอ็อบเจกต์ที่ซ้อนกันไม่รองรับเงื่อนไข has_id หากคุณต้องการใช้ ให้วางไว้ในคลอสข้อความ must ที่ติดกัน

POST /collections/{collection_name}/points/scroll

{
    "filter": {
        "must": [
            "nested": {
                {
                    "key": "diet",
                    "filter": {
                        "must": [
                            {
                                "key": "food",
                                "match": {
                                    "value": "meat"
                                }
                            },
                            {
                                "key": "likes",
                                "match": {
                                    "value": true
                                }
                            }
                        ]
                    }
                }
            },
            { "has_id": [1] }
        ]
    }
}

การตรงกับข้อความอย่างแน่นอน

มีให้ใช้ตั้งแต่เวอร์ชัน 0.10.0

กรณีพิเศษของเงื่อนไข match คือ เงื่อนไขการตรงกันข้อความ text มันช่วยให้คุณสามารถค้นหาข้อความย่อย ๆ โทเคน หรือวลีที่บังคับอยู่ภายในฟิลด์ข้อความ

ข้อความที่ตรงกันอย่างแน่นอนนี้ขึ้นอยู่กับการกำหนดของดัชนีเต็มข้อความ การกำหนดของนี้ถูกนิยามขณะที่ดัชนีเต็มข้อความถูกสร้างขึ้นและอธิบายภายในดัชนีเต็มข้อความ

หากฟิลด์ไม่มีดัชนีเต็มข้อความ งื่อนไขนี้จะทำงานโดยการตรงค่าฟิลด์ข้อความแบบย่อยย่อค่า

{
  "key": "description",
  "match": {
    "text": "ดี และ ราคาถูก"
  }
}

หากคิวรีมีคำหลายคำ งื่อนไขนี้จะได้รับการตรงกันเฉพาะเมื่อคำทุกคำปรากฏในข้อความ

ช่วง

{
  "key": "price",
  "range": {
    "gt": null,
    "gte": 100.0,
    "lt": null,
    "lte": 450.0
  }
}

เงื่อนไข range กำหนดช่วงค่าที่เป็นไปได้สำหรับข้อมูลที่เก็บไว้ หากมีการเก็บค่ามากกว่าหนึ่งค่า ค่าอย่างน้อยหนึ่งค่าควรตรงตามเงื่อนไข

การเปรียบเทียบที่สามารถใช้ได้ได้แก่:

  • gt - มากกว่า
  • gte - มากกว่าหรือเท่ากับ
  • lt - น้อยกว่า
  • lte - น้อยกว่าหรือเท่ากับ

สามารถนำไปใช้กับตัวเลขทศนิยมและข้อมูลจำนวนเต็มได้

กล่องขอบเขตภูมิศาสตร์

{
  "key": "location",
  "geo_bounding_box": {
    "bottom_right": {
      "lat": 52.495862,
      "lon": 13.455868
    },
    "top_left": {
      "lat": 52.520711,
      "lon": 13.403683
    }
  }
}

มันตรงกับ location ภายใน สี่เหลี่ยมผืนดินที่มีพิกัดที่ขวาล่างเป็น bottom_right และพิกัดที่ซ้ายบนเป็น top_left

รัศมีภูมิศาสตร์

{
  "key": "location",
  "geo_radius": {
    "center": {
      "lat": 52.520711,
      "lon": 13.403683
    },
    "radius": 1000.0
  }
}

มันตรงกับ location ภายในวงกลมที่มีศูนย์กลางที่ center และรัศมีที่ radius เมตร

หากมีการเก็บค่ามากกว่าหนึ่งค่า ค่าอย่างน้อยหนึ่งค่าควรตรงตามเงื่อนไข การใช้เงื่อนไขเหล่านี้สามารถนำไปใช้กับข้อมูลภูมิศาสตร์ได้เท่านั้น

จำนวนค่า

นอกจากการเปรียบเทียบค่าโดยตรงแล้ว การกรองยังสามารถขึ้นอยู่กับจำนวนของค่า

ตัวอย่างเช่น ถ้ามีข้อมูลต่อไปนี้:

[
  { "id": 1, "name": "สินค้า A", "comments": ["ดีมาก!", "ยอดเยี่ยม"] },
  { "id": 2, "name": "สินค้า B", "comments": ["พอใช้", "คาดหวังมากขึ้น", "ดี"] }
]

เราสามารถค้นหาเพียงรายการที่มีความคิดเห็นมากกว่าสองคำเท่านั้น:

{
  "key": "comments",
  "values_count": {
    "gt": 2
  }
}

ผลลัพธ์จะเป็น:

[{ "id": 2, "name": "สินค้า B", "comments": ["พอใช้", "คาดหวังมากขึ้น", "ดี"] }]

หากข้อมูลที่เก็บเป็นไม่ใช่อาร์เรย์ จะถือว่าจำนวนค่าเท่ากับ 1 เสมอ

ว่างเปล่า

บางครั้ง การกรองออกบันทึกที่ขาดค่าบางอย่างออกไปจะเป็นประโยชน์ สถานการณ์ที่ใช้เงื่อนไข IsEmpty จะช่วยให้คุณบันทึกล้มเหลว

{
  "is_empty": {
    "key": "รายงาน"
  }
}

เงื่อนไขนี้จะตรงกับบันทึกทั้งหมดที่ฟิลด์ reports ไม่มีอยู่หรือมีค่าเป็น null หรือ []

IsEmpty มักจะมีประโยชน์มากเมื่อใช้ร่วมกับการปฏิเสธทางตรรกะ must_not ในกรณีนี้ มันจะเลือกทุกค่าที่ไม่ว่างเปล่า

เป็นค่าว่าง

เงื่อนไข match ไม่สามารถทดสอบค่า NULL ได้ จะต้องใช้เงื่อนไข IsNull:

{
    "is_null": {
        "key": "รายงาน"
    }
}

เงื่อนไขนี้จะตรงกับบันทึกทั้งหมดที่ฟิลด์ reports มีอยู่และมีค่าเป็น NULL

มี ID

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

POST /collections/{collection_name}/points/scroll

{
    "filter": {
        "must": [
            { "has_id": [1,3,5,7,9,11] }
        ]
    }
  ...
}

จะได้ผลลัพธ์ที่กรองมาว่า:

[
  { "id": 1, "city": "ลอนดอน", "สี": "เขียว" },
  { "id": 3, "city": "ลอนดอน", "สี": "น้ำเงิน" },
  { "id": 5, "city": "มอสโก", "สี": "เขียว" }
]