Tutorial: Membuat penganalisis kustom untuk nomor telepon

Dalam solusi pencarian, string yang memiliki pola kompleks atau karakter khusus dapat menjadi tantangan untuk dikerjakan karena penganalisis default menghapus atau salah menafsirkan bagian pola yang bermakna, menghasilkan pengalaman pencarian yang buruk ketika pengguna tidak dapat menemukan informasi yang mereka harapkan. Telepon angka adalah contoh klasik string yang sulit dianalisis. Mereka datang dalam berbagai format, dan menyertakan karakter khusus yang diabaikan penganalisis default.

Dengan nomor telepon sebagai subjeknya, tutorial ini melihat lebih dekat masalah data berpola, dan menunjukkan kepada Anda untuk menyelesaikan masalah tersebut menggunakan penganalisis kustom. Pendekatan yang diuraikan di sini dapat digunakan apa adanya untuk nomor telepon, atau disesuaikan untuk bidang yang memiliki karakteristik yang sama (berpola, dengan karakter khusus), seperti URL, email, kode pos, dan tanggal.

Dalam tutorial ini, Anda menggunakan klien REST dan REST API Azure AI Search untuk:

  • Memahami masalahnya
  • Mengembangkan penganalisis kustom awal untuk menangani nomor telepon
  • Menguji penganalisis kustom
  • Iterasi pada desain penganalisis kustom untuk meningkatkan hasil lebih lanjut

Prasyarat

Layanan dan alat berikut diperlukan untuk tutorial ini.

Mengunduh file

Kode sumber untuk tutorial ini adalah file custom-analyzer.rest di repositori GitHub Azure-Samples/azure-search-rest-samples .

Menyalin kunci dan URL

Panggilan REST dalam tutorial ini memerlukan titik akhir layanan pencarian dan kunci API admin. Anda bisa mendapatkan nilai-nilai ini dari portal Azure.

  1. Masuk ke portal Azure, navigasikan ke halaman Gambaran Umum, dan salin URL. Contoh titik akhir mungkin terlihat sepertihttps://mydemo.search.windows.net.

  2. Di bawah Pengaturan> Keys, salin kunci admin. Kunci admin digunakan untuk menambahkan, memodifikasi, dan menghapus objek. Ada dua kunci admin yang dapat dipertukarkan. Salin salah satu.

    Screenshot of the URL and API keys in the Azure portal.

Kunci API yang valid menetapkan kepercayaan, berdasarkan per permintaan, antara aplikasi yang mengirim permintaan dan layanan pencarian yang menanganinya.

Membuat indeks awal

  1. Buka file teks baru di Visual Studio Code.

  2. Atur variabel ke titik akhir pencarian dan kunci API yang Anda kumpulkan di langkah sebelumnya.

    @baseUrl = PUT-YOUR-SEARCH-SERVICE-URL-HERE
    @apiKey = PUT-YOUR-ADMIN-API-KEY-HERE
    
  3. Simpan file dengan .rest ekstensi file.

  4. Tempelkan dalam contoh berikut untuk membuat indeks kecil yang disebut phone-numbers-index dengan dua bidang: id dan phone_number. Kami belum menentukan penganalisis, sehingga penganalisis standard.lucene digunakan secara default.

    ### Create a new index
    POST {{baseUrl}}/indexes?api-version=2023-11-01  HTTP/1.1
      Content-Type: application/json
      api-key: {{apiKey}}
    
      {
        "name": "phone-numbers-index",  
        "fields": [
          {
            "name": "id",
            "type": "Edm.String",
            "key": true,
            "searchable": true,
            "filterable": false,
            "facetable": false,
            "sortable": true
          },
          {
            "name": "phone_number",
            "type": "Edm.String",
            "sortable": false,
            "searchable": true,
            "filterable": false,
            "facetable": false
          }
        ]
      }
    
  5. Pilih Kirim Permintaan. Anda harus memiliki HTTP/1.1 201 Created respons dan isi respons harus menyertakan representasi JSON dari skema indeks.

  6. Muat data ke dalam indeks, menggunakan dokumen yang berisi berbagai format nomor telepon. Ini adalah data pengujian Anda.

    ### Load documents
    POST {{baseUrl}}/indexes/phone-numbers-index/docs/index?api-version=2023-11-01  HTTP/1.1
      Content-Type: application/json
      api-key: {{apiKey}}
    
      {
        "value": [
          {
            "@search.action": "upload",  
            "id": "1",
            "phone_number": "425-555-0100"
          },
          {
            "@search.action": "upload",  
            "id": "2",
            "phone_number": "(321) 555-0199"
          },
          {  
            "@search.action": "upload",  
            "id": "3",
            "phone_number": "+1 425-555-0100"
          },
          {  
            "@search.action": "upload",  
            "id": "4",  
            "phone_number": "+1 (321) 555-0199"
          },
          {
            "@search.action": "upload",  
            "id": "5",
            "phone_number": "4255550100"
          },
          {
            "@search.action": "upload",  
            "id": "6",
            "phone_number": "13215550199"
          },
          {
            "@search.action": "upload",  
            "id": "7",
            "phone_number": "425 555 0100"
          },
          {
            "@search.action": "upload",  
            "id": "8",
            "phone_number": "321.555.0199"
          }
        ]  
      }
    
  7. Mari kita coba beberapa kueri yang mirip dengan apa yang mungkin dititik pengguna. Pengguna dapat mencari (425) 555-0100 dalam sejumlah format dan masih mengharapkan hasil dikembalikan. Mulailah dengan mencari (425) 555-0100:

    ### Search for a phone number
    GET {{baseUrl}}/indexes/phone-numbers-index/docs/search?api-version=2023-11-01&search=(425) 555-0100  HTTP/1.1
      Content-Type: application/json
      api-key: {{apiKey}}
    

    Kueri mengembalikan tiga dari empat hasil yang diharapkan, tetapi juga mengembalikan dua hasil yang tidak terduga:

    {
        "value": [
            {
                "@search.score": 0.05634898,
                "phone_number": "+1 425-555-0100"
            },
            {
                "@search.score": 0.05634898,
                "phone_number": "425 555 0100"
            },
            {
                "@search.score": 0.05634898,
                "phone_number": "425-555-0100"
            },
            {
                "@search.score": 0.020766128,
                "phone_number": "(321) 555-0199"
            },
            {
                "@search.score": 0.020766128,
                "phone_number": "+1 (321) 555-0199"
            }
        ]
    }
    
  8. Mari kita coba lagi tanpa pemformatan apa pun: 4255550100.

     ### Search for a phone number
     GET {{baseUrl}}/indexes/phone-numbers-index/docs/search?api-version=2023-11-01&search=4255550100  HTTP/1.1
       Content-Type: application/json
       api-key: {{apiKey}}
    

    Kueri ini bahkan lebih buruk, hanya mengembalikan satu dari empat kecocokan yang benar.

    {
        "value": [
            {
                "@search.score": 0.6015292,
                "phone_number": "4255550100"
            }
        ]
    }
    

Jika menurut Anda hasil ini membingungkan, Anda tidak sendirian. Di bagian berikutnya, mari kita gali mengapa kita mendapatkan hasil ini.

Tinjau cara kerja penganalisis

Untuk memahami hasil pencarian ini, kita perlu memahami apa yang dilakukan penganalisis. Dari sana, kita dapat menguji penganalisis default menggunakan Analyze API, menyediakan fondasi untuk merancang penganalisis yang lebih memenuhi kebutuhan kita.

Penganalisis adalah komponen mesin cari teks lengkap yang bertanggung jawab untuk memproses teks dalam string kueri dan dokumen terindeks. Analis yang berbeda memanipulasi teks dengan cara yang berbeda bergantung pada skenarionya. Untuk skenario ini, kita perlu membangun penganalisis yang disesuaikan untuk nomor telepon.

Penganalisis terdiri dari tiga komponen:

  • Filter karakter yang menghapus atau mengganti karakter individual dari teks input.
  • Tokenizer yang memecah teks input menjadi token, yang menjadi kunci dalam indeks pencarian.
  • Filter token yang memanipulasi token yang dihasilkan oleh tokenizer.

Dalam diagram berikut, Anda dapat melihat bagaimana ketiga komponen ini bekerja sama untuk tokenisasi kalimat:

Diagram of Analyzer process to tokenize a sentence

Token ini kemudian disimpan dalam indeks terbalik, yang memungkinkan pencarian teks lengkap yang cepat. Indeks terbalik memungkinkan pencarian teks lengkap dengan memetakan semua istilah unik yang diekstrak selama analisis leksikal ke dokumen tempatnya terjadi. Anda dapat melihat contoh dalam diagram berikutnya:

Example inverted index

Semua pencarian bermuara untuk mencari istilah yang disimpan dalam indeks terbalik. Saat pengguna mengeluarkan kueri:

  1. Kueri tersebut diurai dan istilah kueri dianalisis.
  2. Indeks terbalik kemudian dipindai untuk mencari dokumen dengan istilah yang cocok.
  3. Terakhir, dokumen yang diambil diberi peringkat oleh algoritma penilaian.

Diagram of Analyzer process ranking similarity

Jika istilah kueri tidak cocok dengan istilah dalam indeks terbalik Anda, hasil tidak dikembalikan. Untuk mempelajari selengkapnya tentang cara kerja kueri, lihat artikel tentang pencarian teks lengkap ini.

Catatan

Kueri istilah parsial adalah pengecualian penting untuk aturan ini. Kueri ini (kueri prefiks, kueri kartubebas, kueri regex) melewati proses analisis leksikal, tidak seperti kueri istilah biasa. Istilah parsial hanya dijadikan huruf kecil sebelum dicocokkan dengan istilah dalam indeks. Jika penganalisis tidak dikonfigurasi untuk mendukung jenis kueri ini, Anda akan sering menerima hasil yang tidak terduga karena istilah yang cocok tidak ada dalam indeks.

Menguji penganalisis menggunakan Analyze API

Azure AI Search menyediakan Analyze API yang memungkinkan Anda menguji penganalisis untuk memahami cara mereka memproses teks.

Analyze API dipanggil menggunakan permintaan berikut:

POST {{baseUrl}}/indexes/phone-numbers-index/analyze?api-version=2023-11-01  HTTP/1.1
  Content-Type: application/json
  api-key: {{apiKey}}

  {
    "text": "(425) 555-0100",
    "analyzer": "standard.lucene"
  }

API mengembalikan token yang diekstrak dari teks, menggunakan penganalisis yang Anda tentukan. Penganalisis Lucene standar membagi nomor telepon menjadi tiga token terpisah:

{
    "tokens": [
        {
            "token": "425",
            "startOffset": 1,
            "endOffset": 4,
            "position": 0
        },
        {
            "token": "555",
            "startOffset": 6,
            "endOffset": 9,
            "position": 1
        },
        {
            "token": "0100",
            "startOffset": 10,
            "endOffset": 14,
            "position": 2
        }
    ]
}

Sebaliknya, nomor telepon 4255550100 yang diformat tanpa tanda baca ditokenisasi menjadi satu token.

{
  "text": "4255550100",
  "analyzer": "standard.lucene"
}

Respons:

{
    "tokens": [
        {
            "token": "4255550100",
            "startOffset": 0,
            "endOffset": 10,
            "position": 0
        }
    ]
}

Perlu diingat bahwa istilah kueri dan dokumen terindeks menjalani analisis. Berpikir kembali ke hasil pencarian dari langkah sebelumnya, kita dapat mulai melihat mengapa hasil tersebut ditampilkan.

Dalam kueri pertama, nomor telepon yang tidak terduga dikembalikan karena salah satu token mereka, 555, cocok dengan salah satu istilah yang kami cari. Di kueri kedua, hanya satu angka yang dikembalikan karena itu adalah satu-satunya rekaman yang memiliki token yang cocok 4255550100.

Membuat penganalisis kustom

Setelah memahami hasil yang kita lihat, mari kita bangun penganalisis kustom untuk meningkatkan logika tokenisasi.

Tujuannya adalah untuk memberikan pencarian intuitif terhadap nomor telepon terlepas dari format kueri atau string terindeks. Untuk mencapai hasil ini, kita akan menentukan filter karakter, tokenizer, dan filter token.

Filter karakter

Filter karakter digunakan untuk memproses teks sebelum disalurkan ke tokenizer. Penggunaan umum filter karakter termasuk memfilter elemen HTML atau mengganti karakter khusus.

Untuk nomor telepon, kita ingin menghapus spasi putih dan karakter khusus karena tidak semua format nomor telepon berisi karakter khusus dan spasi yang sama.

"charFilters": [
    {
      "@odata.type": "#Microsoft.Azure.Search.MappingCharFilter",
      "name": "phone_char_mapping",
      "mappings": [
        "-=>",
        "(=>",
        ")=>",
        "+=>",
        ".=>",
        "\\u0020=>"
      ]
    }
  ]

Filter menghapus -+(). dan spasi dari input.

Input Output
(321) 555-0199 3215550199
321.555.0199 3215550199

Tokenizer

Tokenizer membagi teks menjadi token dan membuang beberapa karakter, seperti tanda baca, dalam prosesnya. Dalam banyak kasus, tujuan tokenisasi adalah untuk membagi kalimat menjadi kata-kata individu.

Untuk skenario ini, kita akan menggunakan tokenizer kata kunci, keyword_v2, karena kita ingin mengambil nomor telepon sebagai satu istilah. Perhatikan bahwa ini bukan satu-satunya cara untuk menyelesaikan masalah ini. Lihat bagian Pendekatan alternatif di bawah ini.

Tokenizer kata kunci selalu menghasilkan teks yang sama dengan yang diberikan sebagai satu istilah.

Input Output
The dog swims. [The dog swims.]
3215550199 [3215550199]

Filter token

Filter token akan memfilter atau memodifikasi token yang dihasilkan oleh tokenizer. Salah satu penggunaan umum filter token adalah untuk mengubah semua karakter menjadi huruf kecil menggunakan filter token huruf kecil. Penggunaan umum lainnya adalah memfilter stopword, seperti the, and, atau is.

Meskipun kita tidak perlu menggunakan salah satu filter tersebut untuk skenario ini, kita akan menggunakan filter token nGram untuk memungkinkan pencarian parsial nomor telepon.

"tokenFilters": [
  {
    "@odata.type": "#Microsoft.Azure.Search.NGramTokenFilterV2",
    "name": "custom_ngram_filter",
    "minGram": 3,
    "maxGram": 20
  }
]

NGramTokenFilterV2

Filter nGram_v2 token membagi token menjadi n-gram dari ukuran tertentu berdasarkan parameter minGram dan maxGram.

Untuk penganalisis telepon, atur minGram menjadi 3 karena itu adalah substring terpendek yang akan dicari pengguna. maxGram diatur ke 20 untuk memastikan bahwa semua nomor telepon, bahkan dengan ekstensi, akan masuk ke dalam satu n-gram.

Efek samping yang disayangkan dari n-gram adalah beberapa positif palsu akan ditampilkan. Kami akan memperbaikinya di langkah selanjutnya dengan membangun penganalisis terpisah untuk pencarian yang tidak menyertakan filter token n-gram.

Input Output
[12345] [123, 1234, 12345, 234, 2345, 345]
[3215550199] [321, 3215, 32155, 321555, 3215550, 32155501, 321555019, 3215550199, 215, 2155, 21555, 215550, ... ]

Penganalisis

Karena filter karakter, tokenizer, dan filter token kami sudah disiapkan, kita siap untuk menentukan penganalisis.

"analyzers": [
  {
    "@odata.type": "#Microsoft.Azure.Search.CustomAnalyzer",
    "name": "phone_analyzer",
    "tokenizer": "keyword_v2",
    "tokenFilters": [
      "custom_ngram_filter"
    ],
    "charFilters": [
      "phone_char_mapping"
    ]
  }
]

Dari Analyze API, dengan input berikut, output dari penganalisis kustom ditampilkan dalam tabel berikut.

Input Output
12345 [123, 1234, 12345, 234, 2345, 345]
(321) 555-0199 [321, 3215, 32155, 321555, 3215550, 32155501, 321555019, 3215550199, 215, 2155, 21555, 215550, ... ]

Semua token dalam kolom output ada dalam indeks. Jika kueri kami menyertakan salah satu istilah tersebut, nomor telepon akan dikembalikan.

Membangun kembali menggunakan penganalisis baru

  1. Hapus indeks saat ini:

     ### Delete the index
     DELETE {{baseUrl}}/indexes/phone-numbers-index?api-version=2023-11-01 HTTP/1.1
         api-key: {{apiKey}}
    
  2. Buat ulang indeks menggunakan penganalisis baru. Skema indeks ini menambahkan definisi penganalisis kustom, dan penetapan penganalisis kustom pada bidang nomor telepon.

    ### Create a new index
    POST {{baseUrl}}/indexes?api-version=2023-11-01  HTTP/1.1
      Content-Type: application/json
      api-key: {{apiKey}}
    
    {
        "name": "phone-numbers-index-2",  
        "fields": [
          {
              "name": "id",
              "type": "Edm.String",
              "key": true,
              "searchable": true,
              "filterable": false,
              "facetable": false,
              "sortable": true
          },
          {
              "name": "phone_number",
              "type": "Edm.String",
              "sortable": false,
              "searchable": true,
              "filterable": false,
              "facetable": false,
              "analyzer": "phone_analyzer"
          }
        ],
        "analyzers": [
            {
              "@odata.type": "#Microsoft.Azure.Search.CustomAnalyzer",
              "name": "phone_analyzer",
              "tokenizer": "keyword_v2",
              "tokenFilters": [
              "custom_ngram_filter"
            ],
            "charFilters": [
              "phone_char_mapping"
              ]
            }
          ],
          "charFilters": [
            {
              "@odata.type": "#Microsoft.Azure.Search.MappingCharFilter",
              "name": "phone_char_mapping",
              "mappings": [
                "-=>",
                "(=>",
                ")=>",
                "+=>",
                ".=>",
                "\\u0020=>"
              ]
            }
          ],
          "tokenFilters": [
            {
              "@odata.type": "#Microsoft.Azure.Search.NGramTokenFilterV2",
              "name": "custom_ngram_filter",
              "minGram": 3,
              "maxGram": 20
            }
          ]
        }
    

Menguji penganalisis kustom

Setelah membuat ulang indeks, Anda sekarang dapat menguji penganalisis menggunakan permintaan berikut:

POST {{baseUrl}}/indexes/tutorial-first-analyzer/analyze?api-version=2023-11-01  HTTP/1.1
  Content-Type: application/json
  api-key: {{apiKey}} 

  {
    "text": "+1 (321) 555-0199",
    "analyzer": "phone_analyzer"
  }

Anda sekarang akan melihat kumpulan token yang dihasilkan dari nomor telepon:

{
    "tokens": [
        {
            "token": "132",
            "startOffset": 1,
            "endOffset": 17,
            "position": 0
        },
        {
            "token": "1321",
            "startOffset": 1,
            "endOffset": 17,
            "position": 0
        },
        {
            "token": "13215",
            "startOffset": 1,
            "endOffset": 17,
            "position": 0
        },
        ...
        ...
        ...
    ]
}

Merevisi penganalisis kustom untuk menangani positif palsu

Setelah membuat beberapa sampel kueri terhadap indeks dengan penganalisis kustom, Anda akan mendapati bahwa ada peningkatan pada pengenalan dan semua nomor telepon yang cocok sekarang ditampilkan. Namun, filter token n-gram menyebabkan beberapa positif palsu ditampilkan juga. Ini adalah efek samping umum dari filter token n-gram.

Untuk mencegah positif palsu, kita akan membuat penganalisis yang terpisah untuk melakukan kueri. Penganalisis ini identik dengan yang sebelumnya, kecuali bahwa penganalisiscustom_ngram_filterini menghilangkan .

    {
      "@odata.type": "#Microsoft.Azure.Search.CustomAnalyzer",
      "name": "phone_analyzer_search",
      "tokenizer": "custom_tokenizer_phone",
      "tokenFilters": [],
      "charFilters": [
        "phone_char_mapping"
      ]
    }

Dalam definisi indeks, kita kemudian menentukan indexAnalyzer dan searchAnalyzer.

    {
      "name": "phone_number",
      "type": "Edm.String",
      "sortable": false,
      "searchable": true,
      "filterable": false,
      "facetable": false,
      "indexAnalyzer": "phone_analyzer",
      "searchAnalyzer": "phone_analyzer_search"
    }

Dengan perubahan ini, Anda sudah siap. Berikut adalah langkah Anda berikutnya:

  1. Hapus indeks.

  2. Buat ulang indeks setelah menambahkan penganalisis kustom baru (phone_analyzer-search) dan menetapkan penganalisis tersebut ke phone-number properti bidang searchAnalyzer .

  3. Muat ulang data.

  4. Coba lagi kueri untuk memverifikasi bahwa pencarian berfungsi seperti yang diharapkan. Jika Anda menggunakan file sampel, langkah ini akan membuat indeks ketiga bernama phone-number-index-3.

Pendekatan alternatif

Penganalisis yang dijelaskan di bagian sebelumnya dirancang untuk memaksimalkan fleksibilitas untuk pencarian. Namun, penganalisis tersebut melakukannya dengan menyimpan banyak istilah yang kemungkinan tidak penting dalam indeks.

Contoh berikut menunjukkan penganalisis alternatif yang lebih efisien dalam tokenisasi, tetapi memiliki kelemahan.

Mengingat input , 14255550100penganalisis tidak dapat secara logis memotong nomor telepon. Misalnya, kode negara tidak dapat dipisahkan, 1, dari kode area, 425. Perbedaan ini akan menyebabkan nomor telepon tidak dikembalikan jika pengguna tidak menyertakan kode negara dalam pencarian mereka.

"analyzers": [
  {
    "@odata.type": "#Microsoft.Azure.Search.CustomAnalyzer",
    "name": "phone_analyzer_shingles",
    "tokenizer": "custom_tokenizer_phone",
    "tokenFilters": [
      "custom_shingle_filter"
    ]
  }
],
"tokenizers": [
  {
    "@odata.type": "#Microsoft.Azure.Search.StandardTokenizerV2",
    "name": "custom_tokenizer_phone",
    "maxTokenLength": 4
  }
],
"tokenFilters": [
  {
    "@odata.type": "#Microsoft.Azure.Search.ShingleTokenFilter",
    "name": "custom_shingle_filter",
    "minShingleSize": 2,
    "maxShingleSize": 6,
    "tokenSeparator": ""
  }
]

Anda dapat melihat dalam contoh berikut bahwa nomor telepon dibagi menjadi potongan yang biasanya Anda harapkan untuk dicari pengguna.

Input Output
(321) 555-0199 [321, 555, 0199, 321555, 5550199, 3215550199]

Tergantung pada kebutuhan Anda, ini mungkin pendekatan yang lebih efisien untuk masalah tersebut.

Poin-poin penting

Tutorial ini menunjukkan proses untuk membangun dan menguji penganalisis kustom. Anda membuat indeks, data terindeks, lalu mengkueri terhadap indeks untuk melihat hasil pencarian apa yang ditampilkan. Dari sana, Anda menggunakan Analyze API untuk melihat proses analisis leksikal yang sedang berjalan.

Meskipun penganalisis yang ditentukan dalam tutorial ini menawarkan solusi mudah untuk mencari nomor telepon, proses yang sama ini dapat digunakan untuk membangun penganalisis kustom untuk skenario apa pun yang berbagi karakteristik serupa.

Membersihkan sumber daya

Saat Anda bekerja di langganan Anda sendiri, sebaiknya hapus sumber daya yang tidak lagi Anda butuhkan di akhir proyek. Sumber daya yang dibiarkan berjalan dapat menghabiskan uang Anda. Anda dapat menghapus sumber daya satu per satu atau menghapus grup sumber daya untuk menghapus seluruh rangkaian sumber daya.

Anda dapat menemukan dan mengelola sumber daya di portal, menggunakan tautan Semua sumber daya atau Grup sumber daya di panel navigasi kiri.

Langkah berikutnya

Sekarang setelah Anda familiar dengan cara membuat penganalisis kustom, mari kita lihat berbagai filter, tokenizer, dan penganalisis yang tersedia bagi Anda untuk membangun pengalaman pencarian yang kaya.