Filtre
Qdrant ile noktaları aramak veya almak için koşullar belirleyebilirsiniz, bu da vektörler için benzerlik aramalarına ek olarak özelliklere göre filtreleme yapabileceğiniz anlamına gelir, SQL where
koşullarını ayarlama gibi. Örneğin, payload ve noktanın id
almak için koşullar belirleyebilirsiniz.
Bir nesnenin tüm özellikleri bir gömme içinde ifade edilemiyorsa ek koşullar belirlemek önemlidir. Örneğin, envanterin kullanılabilirliği, kullanıcı konumu veya beklenen fiyat aralığı gibi çeşitli iş gereksinimleri.
Filtre Koşulları
Qdrant, koşulları ifadelerde birleştirmenize olanak tanır. İfadeler, VEYA
, VE
ve DEĞİL
gibi farklı mantıksal işlemlerdir. İfadeler birbirleri içinde tekrarlı bir şekilde yerleştirilebilir, böylece herhangi bir boolean ifadeyi yeniden oluşturabilirsiniz.
Qdrant'ta uygulanan ifadelere bir göz atalım.
Örneğin, payload'a sahip bir nokta kümemiz olduğunu varsayalım:
[
{ "id": 1, "city": "Londra", "color": "yeşil" },
{ "id": 2, "city": "Londra", "color": "kırmızı" },
{ "id": 3, "city": "Londra", "color": "mavi" },
{ "id": 4, "city": "Berlin", "color": "kırmızı" },
{ "id": 5, "city": "Moskova", "color": "yeşil" },
{ "id": 6, "city": "Moskova", "color": "mavi" }
]
Gereklidir (Must)
Örnek:
POST /collections/{koleksiyon_adı}/noktalar/gezmek
{
"filter": {
"must": [
{ "key": "city", "match": { "value": "Londra" } },
{ "key": "color", "match": { "value": "kırmızı" } }
]
}
...
}
Filtrelenen nokta şu olacaktır:
[{ "id": 2, "city": "Londra", "color": "kırmızı" }]
Must
kullanılırken, şartlar bölümündeki her koşul karşılandığında ifade sadece o zaman true
olur. Bu anlamda, must
, VE
operatörüne eşittir.
Olmalı (Should)
Should
, SQL'deki VEYA
operatörüne benzer.
Örnek:
POST /collections/{koleksiyon_adı}/noktalar/gezmek
{
"filter": {
"should": [
{ "key": "city", "match": { "value": "Londra" } },
{ "key": "color", "match": { "value": "kırmızı" } }
]
}
...
}
Filtrelenen noktalar şunlar olacaktır:
[
{ "id": 1, "city": "Londra", "color": "yeşil" },
{ "id": 2, "city": "Londra", "color": "kırmızı" },
{ "id": 3, "city": "Londra", "color": "mavi" },
{ "id": 4, "city": "Berlin", "color": "kırmızı" }
]
Should
kullanılırken, ifade sadece en az bir koşul karşılandığında true
olur. Bu anlamda, should
, VEYA
operatörüne eşittir.
Olmamalı (must_not)
Örnek:
POST /collections/{koleksiyon_adı}/noktalar/gezmek
{
"filter": {
"must_not": [
{ "key": "city", "match": { "value": "Londra" } },
{ "key": "color", "match": { "value": "kırmızı" } }
]
}
...
}
Filtrelenen noktalar şunlar olacaktır:
[
{ "id": 5, "city": "Moskova", "color": "yeşil" },
{ "id": 6, "city": "Moskova", "color": "mavi" }
]
Must_not
kullanılırken, alt ifade sadece hiçbiri karşılandığında true
olur. Bu anlamda, must_not
, (DEĞİL A) VE (DEĞİL B) VE (DEĞİL C)
ifadesine eşittir.
Koşulların Birleştirilmesi
Çoklu koşulların aynı anda kullanılması mümkündür:
POST /collections/{collection_name}/points/scroll
{
"filter": {
"must": [
{ "key": "city", "match": { "value": "Londra" } }
],
"must_not": [
{ "key": "color", "match": { "value": "kırmızı" } }
]
}
...
}
Filtrelenen noktalar şunlar olacaktır:
[
{ "id": 1, "city": "Londra", "color": "yeşil" },
{ "id": 3, "city": "Londra", "color": "mavi" }
]
Bu durumda koşullar VE
kullanılarak birleştirilmiştir.
Ayrıca, koşullar tekrarlı olarak iç içe yerleştirilebilir. Örneğin:
POST /collections/{collection_name}/points/scroll
{
"filter": {
"must_not": [
{
"must": [
{ "key": "city", "match": { "value": "Londra" } },
{ "key": "color", "match": { "value": "kırmızı" } }
]
}
]
}
...
}
Filtrelenen noktalar şunlar olacaktır:
[
{ "id": 1, "city": "Londra", "color": "yeşil" },
{ "id": 3, "city": "Londra", "color": "mavi" },
{ "id": 4, "city": "Berlin", "color": "kırmızı" },
{ "id": 5, "city": "Moskova", "color": "yeşil" },
{ "id": 6, "city": "Moskova", "color": "mavi" }
]
Koşul Filtreleme
Payload içinde, farklı türdeki değerler, bunlara uygulanabilecek farklı türde sorgulara karşılık gelir. Mevcut koşul varyantlarına ve bunların uygulandığı veri tiplerine bir göz atalım.
Eşleştirme
{
"key": "color",
"match": {
"value": "kırmızı"
}
}
Diğer türler için, eşleştirme koşulları tamamen aynı görünür, sadece farklı türler kullanılır:
{
"key": "count",
"match": {
"value": 0
}
}
En basit koşul, depolanan değerin verilen değere eşit olup olmadığını kontrol eder. Birden fazla değer depolanmışsa, en az bir tanesi koşulu karşılamalıdır. Bu, anahtar kelime, tamsayı ve mantıksal yüklemelere uygulanabilir.
Herhangi Eşleşme
V1.1.0'dan itibaren kullanılabilir
Depolanan değerin birden fazla değerden biri olup olmadığını kontrol etmek istiyorsanız, herhangi eşleşme koşulunu kullanabilirsiniz. Herhangi eşleşme, verilen değeri mantıksal VEYA işlemi olarak ele alır. Aynı zamanda IN
operatörü olarak da tanımlanabilir.
Bu, anahtar kelime ve tamsayı yüklemelere uygulanabilir.
Örnek:
{
"key": "color",
"match": {
"any": ["siyah", "sarı"]
}
}
Bu örnekte, depolanan değer siyah
ya da sarı
ise, koşul karşılanacaktır.
Eğer depolanan değer bir dizi ise, verilen değerlerden herhangi biriyle eşleşen en az bir değere sahip olmalıdır. Örneğin, depolanan değer ["siyah", "yeşil"]
ise, koşul karşılanacaktır çünkü "siyah"
, ["siyah", "sarı"]
içindedir.
Hariç Eşleşme
V1.2.0'dan itibaren kullanılabilir
Depolanan değerin birden fazla değerden hiçbiri olup olmadığını kontrol etmek istiyorsanız, hariç eşleşme koşulunu kullanabilirsiniz. Hariç eşleşme, verilen değeri mantıksal DEĞİL VEYA işlemi olarak ele alır. Aynı zamanda NOT IN
operatörü olarak da tanımlanabilir.
Bu, anahtar kelime ve tamsayı yüklemelere uygulanabilir.
Örnek:
{
"key": "color",
"match": {
"except": ["siyah", "sarı"]
}
}
Bu örnekte, depolanan değer ne siyah
ne de sarı
ise, koşul karşılanacaktır.
Eğer depolanan değer bir dizi ise, verilen değerlerden herhangi biriyle eşleşmeyen en az bir değere sahip olmalıdır. Örneğin, depolanan değer ["siyah", "yeşil"]
ise, koşul karşılanacaktır çünkü "yeşil"
, "siyah"
veya "sarı"
ile eşleşmez.
İç İçe Anahtarlar
V1.1.0'dan itibaren kullanılabilir
Payload'in keyfi bir JSON nesnesi olduğu için iç içe geçmiş alanları filtrelemeniz gerekebilir.
Kolaylık sağlamak için, Jq projesine benzer bir sözdizimi kullanıyoruz.
Aşağıdaki payload'a sahip bir puan setimiz olduğunu varsayalım:
[
{
"id": 1,
"country": {
"name": "Almanya",
"cities": [
{
"name": "Berlin",
"population": 3.7,
"sightseeing": ["Brandenburg Kapısı", "Reichstag"]
},
{
"name": "Münih",
"population": 1.5,
"sightseeing": ["Marienplatz", "Olympiapark"]
}
]
}
},
{
"id": 2,
"country": {
"name": "Japonya",
"cities": [
{
"name": "Tokyo",
"population": 9.3,
"sightseeing": ["Tokyo Kulesi", "Tokyo Skytree"]
},
{
"name": "Osaka",
"population": 2.7,
"sightseeing": ["Osaka Kalesi", "Universal Studios Japonya"]
}
]
}
}
]
Nokta notasyonunu kullanarak iç içe geçmiş alanları arayabilirsiniz.
POST /collections/{collection_name}/points/scroll
{
"filter": {
"should": [
{
"key": "country.name",
"match": {
"value": "Almanya"
}
}
]
}
}
Ayrıca [ ]
sözdizimini kullanarak iç içe diziyi içindeki değerleri projelendirebilirsiniz.
POST /collections/{collection_name}/points/scroll
{
"filter": {
"should": [
{
"key": "country.cities[].population",
"range": {
"gte": 9.0,
}
}
]
}
}
Bu sorgu, yalnızca 2 numaralı noktayı çıktı olarak verir, çünkü sadece Japonya'nın nüfusu 9.0'dan büyük bir şehri vardır.
İç içe alanlar aynı zamanda bir dizi olabilir.
POST /collections/{collection_name}/points/scroll
{
"filter": {
"should": [
{
"key": "country.cities[].sightseeing",
"match": {
"value": "Osaka Kalesi"
}
}
]
}
}
Bu sorgu, sadece 2 numaralı noktayı çıktı olarak verir, çünkü sadece Japonya'nın "Osaka Kalesi"ni içeren bir şehri vardır.
İç İçe Geçmiş Nesne Filtreleme
1.2.0 sürümünden itibaren kullanılabilir
Varsayılan olarak, koşullar bir noktanın tüm veri yükünü dikkate alır.
Örneğin, aşağıdaki veri yükündeki iki nokta verildiğinde:
[
{
"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}
]
}
]
Aşağıdaki sorgu, bu iki noktayı eşleştirir:
POST /collections/{collection_name}/points/scroll
{
"filter": {
"must": [
{
"key": "diet[].food",
"match": {
"value": "meat"
}
},
{
"key": "diet[].likes",
"match": {
"value": true
}
}
]
}
}
Yukarıdaki iki noktanın eşleştirilmesinin nedeni, her ikisinin de aşağıdaki iki koşulu karşılamasıdır:
- "t-rex",
diet[1].food
ile food = meat vediet[1].likes
ile likes = true koşullarını karşılar - "diplodocus",
diet[1].food
ile food = meat vediet[0].likes
ile likes = true koşullarını karşılar
Örneğin bu örnekte id'si 1 olan noktaların koşulları karşılayan noktaları yalnızca elde etmek için iç içe geçmiş nesne filtrelerini kullanmanız gerekmektedir.
İç içe geçmiş nesne filtreleri, nesne dizilerini bağımsız olarak sorgulamayı sağlar.
Bu, ilgi alanı anahtarını ve uygulanacak filtreleri içeren nested
koşul türünü kullanarak başarılabilmektedir.
Anahtar, bir nesne dizisine işaret etmeli ve opsiyonel olarak köşeli parantez notasyonu ("veri" veya "veri[]") kullanabilir.
POST /collections/{collection_name}/points/scroll
{
"filter": {
"must": [
"nested": {
{
"key": "diet",
"filter": {
"must": [
{
"key": "food",
"match": {
"value": "meat"
}
},
{
"key": "likes",
"match": {
"value": true
}
}
]
}
}
}
]
}
}
Eşleşme mantığı, yük içindeki dizi öğe seviyesinde uygulanacak şekilde değiştirilmiştir.
İç içe geçmiş filtre, bir dizi öğesine iç içe geçmiş bir filtre uygulandığında aynı şekilde çalışır. Dizi öğelerinden en az birinin iç içe geçmiş filtreyi karşıladığı sürece, ana belge koşulu karşılandığı kabul edilir.
Sınırlama
İç içe geçmiş nesne filtreleri, has_id
koşulunu desteklemez. Onu kullanmanız gerekiyorsa, yan yana bir must
kalıbına yerleştirin.
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] }
]
}
}
Tam Metin Eşleşmesi
0.10.0 sürümünden itibaren kullanılabilir
match
koşulunun özel bir durumu, text
eşleme koşuludur. Metin alanı içinde belirli alt dizgileri, belirteçleri veya ifadeleri aramanıza olanak tanır.
Bu koşulu karşılayan tam metinler, tam metin dizininin yapılandırmasına bağlıdır. Yapılandırma, dizin oluşturulurken tanımlanır ve tam metin dizini içinde açıklanmıştır.
Eğer alanda tam metin dizini yoksa, bu koşul tam alt dizgi eşleştirmesine dayalı olarak çalışacaktır.
{
"key": "description",
"match": {
"text": "iyi ve ucuz"
}
}
Sorguda birden fazla kelime varsa, bu koşul, tüm kelimelerin metinde göründüğü zaman yalnızca karşılanmış olacaktır.
Aralık
{
"key": "price",
"range": {
"gt": null,
"gte": 100.0,
"lt": null,
"lte": 450.0
}
}
range
koşulu, depolanan verilerin olası değer aralığını belirler. Birden fazla değer depolanmışsa, en az bir değer koşulu karşılamalıdır.
Kullanılabilir karşılaştırma operasyonları şunları içerir:
-
gt
- büyük -
gte
- büyük veya eşit -
lt
- küçük -
lte
- küçük veya eşit
Bu, kesirli sayılar ve tam sayılı payloadlara uygulanabilir.
Coğrafi Sınırlı Kutu
{
"key": "location",
"geo_bounding_box": {
"bottom_right": {
"lat": 52.495862,
"lon": 13.455868
},
"top_left": {
"lat": 52.520711,
"lon": 13.403683
}
}
}
Bu, bottom_right
olarak koordinatları olan dikdörtgen içindeki location
'ı top_left
olarak eşleştirir.
Coğrafi Yarıçap
{
"key": "location",
"geo_radius": {
"center": {
"lat": 52.520711,
"lon": 13.403683
},
"radius": 1000.0
}
}
Bu, merkezi center
olan ve radius
metre yarıçaplı dairenin içindeki location
'ı eşleştirir.
Birden fazla değer depolanmışsa, en az bir değer koşulu karşılamalıdır. Bu koşullar yalnızca coğrafi veri formatına uyan payloadlara uygulanabilir.
Değer Sayısı
Doğrudan değer karşılaştırmasının yanı sıra, filtreleme aynı zamanda değer sayısına göre de olabilir.
Örneğin, aşağıdaki veriler verildiğinde:
[
{ "id": 1, "name": "Ürün A", "comments": ["Çok iyi!", "Mükemmel"] },
{ "id": 2, "name": "Ürün B", "comments": ["Orta", "Daha fazlasını bekliyorum", "İyi"] }
]
Sadece iki yorumdan fazlası olan öğeleri arayabiliriz:
{
"key": "comments",
"values_count": {
"gt": 2
}
}
Sonuç şu olacaktır:
[{ "id": 2, "name": "Ürün B", "comments": ["Orta", "Daha fazlasını bekliyorum", "İyi"] }]
Depolanan değer bir dizi değilse, değer sayısının 1'e eşit olduğu varsayılır.
Boş mu?
Bazı durumlarda, belirli değerlere sahip olmayan kayıtları filtrelemek faydalı olabilir. IsEmpty
koşulu bunu başarmanıza yardımcı olabilir:
{
"is_empty": {
"key": "raporlar"
}
}
Bu koşul, raporlar
alanı mevcut değilse veya bir null
veya []
değerine sahipse tüm kayıtları eşleştirir.
IsEmpty, mantıksal inkar must_not ile birlikte kullanıldığında genellikle çok faydalıdır. Bu durumda, tüm dolu olmayan değerleri seçecektir.
Null mu?
match koşulu, NULL
değerlerini test edemez. IsNull
koşulunu kullanmalıyız:
{
"is_null": {
"key": "raporlar"
}
}
Bu koşul, raporlar
alanı varsa ve bir NULL
değerine sahipse tüm kayıtları eşleştirir.
ID Var mı?
Bu tür sorgu, payloadlarla ilgili olmayıp, belirli durumlarda çok kullanışlıdır. Örneğin, kullanıcılar belirli arama sonuçlarını önemsiz olarak etiketlemek isteyebilir veya belirli noktalar arasında arama yapmak isteyebiliriz.
POST /collections/{collection_name}/points/scroll
{
"filter": {
"must": [
{ "has_id": [1,3,5,7,9,11] }
]
}
...
}
Filtrelenmiş noktalar:
[
{ "id": 1, "şehir": "Londra", "renk": "yeşil" },
{ "id": 3, "şehir": "Londra", "renk": "mavi" },
{ "id": 5, "şehir": "Moskova", "renk": "yeşil" }
]