【Cognitive Search】インデックスのデータをREST API経由で操作してみる

# 概要
Cognitive Search はデータのインポートから各リソースを作成すれば、
深く考えずとも、インデックス・インデクサー・データソース・スキルセットが作成されるが、
今回は敢えて一番原始的な方法として、
空のインデックスだけを作成し、そこにREST API経由でデータを突っ込んで、いろいろ操作してみます。

https://learn.microsoft.com/ja-jp/rest/api/searchservice/AddUpdate-or-Delete-Documents

# 試す
## インデックス作成
ちょっと流行りは過ぎた感じがするけど、ぼざろのキャラ一覧をインデックスにしてみましょうか。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2420694/76c398ea-5312-03e5-a717-2382ccfed613.png)

インデックスは通常どおりAzureポータルから作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2420694/19422a66-8a0e-a77f-cf2f-f5f6589f8103.png)

## データ追加
これで空のインデックスが作成できましたが、当然空なのでここにデータを突っ込む必要があります。
現状、AzurePortalからデータを直接突っ込むことはできないようなので、これをしようとすると、REST APIを使う必要があります。
仕組みは簡単で、作成したインデックスのエンドポイント宛に追加するデータのJSONをPOSTするだけです。

ひとまず、ぼっちちゃんを格納してみましょう。
```python
import requests
import json

def send_json_post_request(url, data):
    headers = {
        "Content-Type": "application/json",
        "api-key": "[Cognitive Search のキーを使う]"
    }
    
    response = requests.post(url, data=json.dumps(data), headers=headers)
    return response

# 送信したいJSONデータを作成します
data_to_send = {
  "value": [  
    {  
      "@search.action": "upload", 
      "id": "1",
      "name": "後藤 ひとり",
      "age": "15",
      "school": "下北沢高校",
      "instrument": "guitar",
      "instrumentDetail": ["ギブソン・レスポール・カスタム","YAMAHA PACIFICA661"],
      "memo": "すぐに溶ける。でかい。"
    }
  ]
}


# POSTリクエストを送信するURLを指定します
target_url = "[リクエスト先のエンドポイント（公式ドキュメントを参照）]"

# JSONデータを含むPOSTリクエストを送信します
response = send_json_post_request(target_url, data_to_send)

# レスポンスを確認します
print(response.status_code)  # ステータスコードを表示
print(response.json())       # レスポンスデータを表示 (JSON形式)
```

このコードを実行して、エラーがなければ以下のように帰ってきます。
```
200
{'@odata.context': "https://[service-name].search.windows.net/indexes('botti-the-rock-character-index')/$metadata#Collection(Microsoft.Azure.Search.V2021_04_30_Preview.IndexResult)", 'value': [{'key': '1', 'status': True, 'errorMessage': None, 'statusCode': 201}]}
```

Azure Portalの画面からインデックスを検索してみると、データが入ってることがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2420694/e840606a-f065-a6e5-1a4c-d1df0d991ba7.png)

こんな感じで単純にデータを突っ込むことができます。他のキャラクターについても入れていきます。
```json
data_to_send = {
  "value": [  
    {  
      "@search.action": "upload", 
      "id": "2",
      "name": "喜多 郁代",
      "age": "16",
      "school": "下北沢高校",
      "instrument": "guitar",
      "instrumentDetail": ["レスポール・ジュニア"],
      "memo": "ｷﾀｰﾝ"
    },
    {  
      "@search.action": "upload", 
      "id": "3",
      "name": "伊地知 虹花",
      "age": "17",
      "school": "秀華高校",
      "instrument": "dram",
      "instrumentDetail": ["TAMA Imperialstar"],
      "memo": "小さい"
    },
    {  
      "@search.action": "upload", 
      "id": "4",
      "name": "山田 リョウ",
      "age": "16",
      "school": "秀華高校",
      "instrument": "bass",
      "instrumentDetail": ["American Professional Precision Bass"],
      "memo": "草食ってるイメージ"
    },
  ]
}
```
※ 筆者は楽器とか知らんので調べたやつ適当に入れてます

これでデータが入りました。
インデックスにページからCognitive Searchでデータが検索できることがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2420694/5965649c-e906-a734-966f-4ac76b8f2bb8.png)

## 更新
データの更新は、アップロードと同じで
**"@search.action": "upload"** でデータを送信する。
ドキュメントキー（id）に対応するデータが更新されます。

## 削除
データを削除する場合は
**"@search.action": "delete"** で実行します。

```json
  "value": [  
    {  
      "@search.action": "delete", 
      "id": "2",
      "name": "喜多 郁代",
      "age": "16",
      "school": "下北沢高校",
      "instrument": "guitar",
      "instrumentDetail": ["レスポール・ジュニア"],
      "memo": "ｷﾀｰﾝ"
    }
  ]
```
※ 喜多ちゃんを消すことに他意はない

なお、削除の場合はドキュメントキー（id）のみの指定でも大丈夫です。

## 参照
REST API経由でのデータ参照も可能です。

https://learn.microsoft.com/ja-jp/rest/api/searchservice/lookup-document

```python
import requests

def send_get_request(url):
    headers = {
    "Content-Type": "application/json",
            "api-key": "[APIキーを指定]"
            }
    response = requests.get(url,headers=headers)
    return response

# GETリクエストを送信するURLを指定します
target_url = "https://[service-name].search.windows.net/indexes/botti-the-rock-character-index/docs/1?api-version=2021-04-30-Preview"

# GETリクエストを送信します
response = send_get_request(target_url)

# レスポンスを確認します
print(response.status_code)  # ステータスコードを表示
print(response.json())       # レスポンスデータを表示 (JSON形式)
```

この場合のレスポンスは以下のとおり。キーに指定した「1」に対応する、ぼっちちゃんの情報が返ってきます。
```
200
{'@odata.context': "https://[service-name].search.windows.net/indexes('botti-the-rock-character-index')/$metadata#docs(*)/$entity", 'id': '1', 'name': '後藤 ひとり', 'age': 15, 'school': '下北沢高
校', 'instrument': 'guitar', 'instrumentDetail': ['ギブソン・レスポール・カスタム', 'YAMAHA PACIFICA661'], 'memo': 'すぐに溶ける。でかい。'}
```

## 検索
検索も当然REST API経由で実行できます。

https://learn.microsoft.com/ja-jp/rest/api/searchservice/search-documents


```python
import requests
import json

def send_json_post_request(url, data):
    headers = {
        "Content-Type": "application/json",
               "api-key": "[APIキー]"
               }
    response = requests.post(url, data=json.dumps(data), headers=headers)
    return response

# 送信したいJSONデータを作成します
data_to_send = {  
     "search": "guitar",  
     "select": "name,school,memo"
   }  


# POSTリクエストを送信するURLを指定します
target_url = "https://[service-name].search.windows.net/indexes/botti-the-rock-character-index/docs/search?api-version=2021-04-30-Preview"

# JSONデータを含むPOSTリクエストを送信します
response = send_json_post_request(target_url, data_to_send)

# レスポンスを確認します
print(response.status_code)  # ステータスコードを表示
print(response.json())       # レスポンスデータを表示 (JSON形式)
```

実行すると、下記のようなデータが返ってきます。
```
200
{'@odata.context': "https://[service-name].search.windows.net/indexes('botti-the-rock-character-index')/$metadata#docs(*)", 'value': [{'@search.score': 0.47000363, 'name': '喜多 郁代', 'school': '下北沢高校', 'memo': 'ｷﾀｰﾝ'}, {'@search.score': 0.2876821, 'name': '後藤 ひとり', 'school': '下北沢高校', 'memo': 'すぐに溶ける。でかい。'}]}
```
検索は、POSTするJSONの内容に応じて検索の仕組みを調整することが可能です。
詳細は公式ドキュメントを参照ということで。

# おわり
今回は敢えてAPI経由でやってみました。
この操作が必要かと言われるとケースバイケースですけども、何でもやってみることに意味があるんじゃないのかなぁ、と。

ちなみに私はぼざろニワカです。アニメしか見とらん！