Memahami cara kerja filter koleksi OData di Azure AI Search

Artikel ini menyediakan latar belakang untuk pengembang yang menulis filter tingkat lanjut dengan ekspresi lambda yang kompleks. Artikel ini menjelaskan mengapa aturan untuk filter koleksi ada dengan mengeksplorasi bagaimana Azure AI Search menjalankan filter ini.

Saat Anda membuat filter pada bidang koleksi di Azure AI Search, Anda dapat menggunakananyoperator dan all bersama dengan ekspresi lambda. Ekspresi lambda adalah ekspresi Boolean yang merujuk pada variabel rentang. Dalam filter yang menggunakan ekspresi lambda, any operator dan all dianalogikan dengan for perulangan dalam sebagian besar bahasa pemrograman, dengan variabel rentang mengambil peran variabel perulangan, dan ekspresi lambda sebagai isi perulangan. Variabel rentang menggunakan nilai "saat ini" dari kumpulan selama iterasi perulangan.

Setidaknya, seperti itulah cara kerjanya secara konseptual. Pada kenyataannya, Azure AI Search mengimplementasikan filter dengan cara yang sangat berbeda untuk cara for kerja perulangan. Idealnya, perbedaan ini dapat Anda lihat, tetapi di situasi tertentu kemungkinan sebaliknya dapat terjadi. Hasil akhirnya adalah, ada aturan yang harus Anda ikuti saat menulis ekspresi lambda.

Catatan

Untuk informasi tentang apa aturan untuk filter koleksi, termasuk contoh, lihat Pemecahan masalah filter kumpulan OData di Azure AI Search.

Alasan terbatasnya filter kumpulan

Ada tiga alasan mendasar mengapa fitur filter tidak sepenuhnya didukung untuk semua jenis koleksi:

  1. Hanya operator tertentu yang didukung untuk jenis data tertentu. Misalnya, membandingkan nilai Boolean true dan false menggunakan lt, gt tidak masuk akal, dan seterusnya.
  2. Pencarian Azure AI tidak mendukung pencarian berkorelasi pada bidang jenis Collection(Edm.ComplexType).
  3. Azure AI Search menggunakan indeks terbalik untuk menjalankan filter di semua jenis data, termasuk koleksi.

Alasan pertama hanyalah konsekuensi dari bagaimana bahasa OData dan sistem jenis EDM ditentukan. Dua alasan terakhir dijelaskan dengan detail lebih terperinci dalam artikel ini.

Saat Anda menerapkan beberapa kriteria filter atas kumpulan objek kompleks, kriteria berkorelasi karena diterapkan ke setiap objek dalam koleksi. Misalnya, filter berikut mengembalikan hotel yang memiliki setidaknya satu kamar deluxe dengan tarif kurang dari 100:

    Rooms/any(room: room/Type eq 'Deluxe Room' and room/BaseRate lt 100)

Jika pemfilteran tidak berkorelasi, filter di atas mungkin menampilkan hotel yang satu kamarnya bertipe deluxe dan kamar lainnya memiliki tarif dasar kurang dari 100. Filter tersebut tidak masuk akal, karena kedua klausa ekspresi lambda berlaku untuk variabel rentang yang sama, bernama room. Oleh karena itulah filter tersebut berkorelasi.

Namun, untuk pencarian teks lengkap, Anda tidak dapat mereferensikan ke variabel rentang yang spesifik. Jika Anda menggunakan pencarian berbidang untuk menerbitkan kueri Lucene lengkap seperti berikut:

    Rooms/Type:deluxe AND Rooms/Description:"city view"

Anda mungkin mendapatkan hotel kembali di mana satu kamar deluxe, dan kamar yang berbeda menyebutkan "pemandangan kota" dalam deskripsi. Misalnya, dokumen berikut dengan Id dari 1 akan menyesuaikan kueri:

{
  "value": [
    {
      "Id": "1",
      "Rooms": [
        { "Type": "deluxe", "Description": "Large garden view suite" },
        { "Type": "standard", "Description": "Standard city view room" }
      ]
    },
    {
      "Id": "2",
      "Rooms": [
        { "Type": "deluxe", "Description": "Courtyard motel room" }
      ]
    }
  ]
}

Alasannya adalah Rooms/Type mengacu pada semua istilah yang dianalisis pada bidang Rooms/Type di seluruh dokumen, dan begitu juga dengan Rooms/Description, seperti yang ditampilkan dalam tabel berikut.

Bagaimana Rooms/Type disimpan untuk pencarian teks lengkap:

Istilah dalam Rooms/Type ID Dokumen
deluxe 1, 2
standar 1

Bagaimana Rooms/Description disimpan untuk pencarian teks lengkap:

Istilah dalam Rooms/Description ID Dokumen
halaman 2
kota 1
taman 1
besar 1
motel 2
kamar 1, 2
standar 1
suite 1
view 1

Jadi tidak seperti filter di atas, yang dasarnya berisi keterangan "menyesuaikan dokumen jika sebuah kamar memiliki Type yang sama dengan 'Kamar Deluxe' dan kamar yang sama tersebut memiliki BaseRate yang kurang dari 100", kueri pencarian menerangkan "menyesuaikan dokumen jika Rooms/Type memiliki istilah "deluxe" dan Rooms/Description memiliki frasa "panorama kota". Tidak ada konsep kamar perorangan yang bidangnya dapat berkorelasi dalam kasus yang lebih baru.

Kumpulan dan indeks terbalik

Anda mungkin telah memperhatikan bahwa ada batasan yang jauh lebih sedikit pada ekspresi lambda atas koleksi kompleks daripada ada untuk koleksi sederhana seperti Collection(Edm.Int32), Collection(Edm.GeographyPoint), dan sebagainya. Ini karena Azure AI Search menyimpan koleksi kompleks sebagai kumpulan subdokumen aktual, sementara koleksi sederhana tidak disimpan sebagai koleksi sama sekali.

Misalnya, pertimbangkan bidang kumpulan string yang dapat difilter seperti seasons di indeks untuk retailer online. Beberapa dokumen yang diunggah ke indeks ini mungkin tampak seperti berikut:

{
  "value": [
    {
      "id": "1",
      "name": "Hiking boots",
      "seasons": ["spring", "summer", "fall"]
    },
    {
      "id": "2",
      "name": "Rain jacket",
      "seasons": ["spring", "fall", "winter"]
    },
    {
      "id": "3",
      "name": "Parka",
      "seasons": ["winter"]
    }
  ]
}

Nilai bidang seasons disimpan dalam struktrur yang disebut indeks terbalik, yang terlihat seperti berikut:

Term ID Dokumen
musim semi 1, 2
musim panas 1
musim gugur 1, 2
musim dingin 2, 3

Struktur data ini dirancang untuk menjawab satu pertanyaan dengan sangat cepat: Di dokumen mana istilah tertentu muncul? Menjawab pertanyaan ini lebih berfungsi seperti pemeriksaan persamaan biasa dibanding perulangan melalui kumpulan. Bahkan, inilah sebabnya mengapa untuk koleksi string, Azure AI Search hanya memungkinkan eq sebagai operator perbandingan di dalam ekspresi lambda untuk any.

Selanjutnya, kita melihat bagaimana dimungkinkan untuk menggabungkan beberapa pemeriksaan kesetaraan pada variabel rentang yang sama dengan or. Cara ini efektif berkat aljabar dan properti pembilang distributif. Ekspresi ini:

    seasons/any(s: s eq 'winter' or s eq 'fall')

setara dengan:

    seasons/any(s: s eq 'winter') or seasons/any(s: s eq 'fall')

dan setiap dua subekspresi any dapat dijalankan secara efektif menggunakan indeks terbalik. Selain itu, berkat hukum negasi pembilang, ekspresi ini:

    seasons/all(s: s ne 'winter' and s ne 'fall')

setara dengan:

    not seasons/any(s: s eq 'winter' or s eq 'fall')

yang menjadi alasan kita dapat menggunakan all dengan ne dan and.

Catatan

Meskipun detail tersebut ada di luar cakupan dokumen ini, prinsip yang sama juga dapat diterapkan pada jarak dan pengujian irisan untuk kumpulan titik geo-spasial. Inilah alasan mengapa, dalam any:

  • geo.intersects tidak dapat dinegasikan
  • geo.distance harus dibandingkan menggunakan lt atau le
  • Ekspresi harus digabungkan dengan or, bukan and

Aturan sebaliknya berlaku untuk all.

Variasi ekspresi jenis data yang lebih beragam diizinkan saat memfilter kumpulan jenis data yang mendukung operator lt, gt, le, dan ge, misalnya ambil Collection(Edm.Int32) sebagai contoh. Secara khusus, Anda dapat menggunakan and sebagaimana or di any, asalkan ekspresi perbandingan yang mendasarinya digabungkan ke perbandingan rentang menggunakan and, yang kemudian digabungkan lebih lanjut menggunakan or. Struktur ungkapan Boolean disebut dengan Disjunctive Normal Form (DNF), atau yang dikenal dengan "OR of AND". Sebaliknya, ekspresi lambda untuk all pada jenis data ini di harus berada dalam Conjunctive Normal Form (CNF), atau dikenal dengan "AND of OR". Azure AI Search memungkinkan perbandingan rentang tersebut karena dapat menjalankannya menggunakan indeks terbalik secara efisien, sama seperti dapat melakukan pencarian jangka cepat untuk string.

Kesimpulannya, berikut aturan praktis terkait hal-hal yang diizinkan dalam ekspresi lambda:

  • Dalam any, pemeriksaan positif selalu diizinkan, seperti persamaan, perbandingan rentang, geo.intersects, atau geo.distance dibandingkan dengan lt atau le (bayangkan "kemiripan" sebagai persamaan jika berkaitan dengan pemeriksaan jarak).
  • Dalam any, or selalu diizinkan. Anda hanya dapat menggunakan and untuk data yang mengungkapkan pemeriksaan rentang, dan hanya jika Anda menggunakan OR of AND (DNF).
  • Di dalam all, aturan dibalik. Hanya pemeriksaan negatif yang diizinkan, Anda dapat menggunakan and selalu, dan Anda hanya dapat menggunakan or untuk pemeriksaan rentang yang dinyatakan sebagai ID OU (CNF).

Dalam praktiknya, ini adalah jenis filter yang sebagian besar akan Anda gunakan. Meskipun demikian, memahami batasan kemungkinan tetaplah bermanfaat.

Untuk mengetahui contoh filter apa saja yang diizinkan atau yang tidak diizinkan, lihat Cara menulis filter kumpulan yang valid.

Langkah berikutnya