オートコンプリートは、あらかじめ登録されているデータに沿って、クエリの変換候補を提示する機能です。
日本語検索プラグインである Kuromoji では、オートコンプリートを簡単に実装できる Kuromoji completion を提供しています。
本ラボでは、同機能を使用した日本語向けのサジェスタを実装します。
本ラボでは、ノートブック環境(JupyterLab) および Amazon OpenSearch Service を使用します。
本ラボでは、 Geolonia が CC BY 4.0 ライセンスの元で配布している 住所データツール v2 データセット を使用します。
!pip install opensearch-py requests-aws4auth "awswrangler[opensearch]" --quiet
import boto3
import json
import logging
import awswrangler as wr
import pandas as pd
from opensearchpy import OpenSearch, RequestsHttpConnection, AWSV4SignerAuth
以降の処理を実行する際に必要なヘルパー関数を定義しておきます。
def search_cloudformation_output(stackname, key):
cloudformation_client = boto3.client("cloudformation", region_name=default_region)
for output in cloudformation_client.describe_stacks(StackName=stackname)["Stacks"][0]["Outputs"]:
if output["OutputKey"] == key:
return output["OutputValue"]
raise ValueError(f"{key} is not found in outputs of {stackname}.")
default_region = boto3.Session().region_name
logging.getLogger().setLevel(logging.ERROR)
OpenSearch クラスターへのネットワーク接続性が確保されており、OpenSearch の Security 機能により API リクエストが許可されているかを確認します。
レスポンスに cluster_name や cluster_uuid が含まれていれば、接続確認が無事完了したと判断できます
cloudformation_stack_name = "search-lab-jp"
opensearch_cluster_endpoint = search_cloudformation_output(cloudformation_stack_name, "OpenSearchDomainEndpoint")
credentials = boto3.Session().get_credentials()
service_code = "es"
auth = AWSV4SignerAuth(credentials=credentials, region=default_region, service=service_code)
opensearch_client = OpenSearch(
hosts=[{"host": opensearch_cluster_endpoint, "port": 443}],
http_compress=True,
http_auth=auth,
use_ssl=True,
verify_certs=True,
connection_class = RequestsHttpConnection
)
opensearch_client.info()
{'name': '37fa7880d30e6918860bdb0e18c8e91d', 'cluster_name': '123456789012:opensearchservi-lsy27q89mdpe', 'cluster_uuid': 'yHC8ufTTRdWZqY-0J9kE9A', 'version': {'distribution': 'opensearch', 'number': '2.17.0', 'build_type': 'tar', 'build_hash': 'unknown', 'build_date': '2025-02-14T09:38:50.023788640Z', 'build_snapshot': False, 'lucene_version': '9.11.1', 'minimum_wire_compatibility_version': '7.10.0', 'minimum_index_compatibility_version': '7.0.0'}, 'tagline': 'The OpenSearch Project: https://opensearch.org/'}
テスト用のインデックスを作成します。今回はサジェスタとして Kuromoji Completion を使用します。
Kuromoji Completion は日本語をローマ字のタームに変換し、completion タイプのフィールドに格納することでサジェストを実現しています。
dataset_dir = "./dataset/japanese-addresses-v2"
dataset_file_path = f"{dataset_dir}/ja.json"
%mkdir -p $dataset_dir
!curl -o {dataset_file_path} https://japanese-addresses-v2.geoloniamaps.com/api/ja.json
% Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 306k 100 306k 0 0 3647k 0 --:--:-- --:--:-- --:--:-- 3650k
file = json.loads(open(dataset_file_path).read())
pref_df = pd.json_normalize(file, ["data"]).explode("cities").rename(columns={
"code": "pref_code",
"pref": "pref_name_kanji",
"pref_k": "pref_name_kana",
"pref_r": "pref_name_romaji",
"point": "pref_point"
})
cities_df = pd.json_normalize(pref_df["cities"]).rename(columns={
"code": "city_code",
"point": "city_point",
"city": "city_name_kanji",
"city_k": "city_name_kana",
"city_r": "city_name_romaji",
"ward": "ward_name_kanji",
"ward_k": "ward_name_kana",
"ward_r": "ward_name_romaji",
"county": "county_name_kanji",
"county_k": "county_name_kana",
"county_r": "county_name_romaji"
})
japanese_addresses_v2_df = pd.concat([pref_df.reset_index(drop=True).drop('cities', axis=1), cities_df], axis=1)
japanese_addresses_v2_df
pref_code | pref_name_kanji | pref_name_kana | pref_name_romaji | pref_point | city_code | city_name_kanji | city_name_kana | city_name_romaji | ward_name_kanji | ward_name_kana | ward_name_romaji | city_point | county_name_kanji | county_name_kana | county_name_romaji | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 10006 | 北海道 | ホッカイドウ | Hokkaido | [141.347906782, 43.0639406375] | 11011 | 札幌市 | サッポロシ | Sapporo-shi | 中央区 | チュウオウク | Chuo-ku | [141.35389, 43.061414] | NaN | NaN | NaN |
1 | 10006 | 北海道 | ホッカイドウ | Hokkaido | [141.347906782, 43.0639406375] | 11029 | 札幌市 | サッポロシ | Sapporo-shi | 北区 | キタク | Kita-ku | [141.340882, 43.090693] | NaN | NaN | NaN |
2 | 10006 | 北海道 | ホッカイドウ | Hokkaido | [141.347906782, 43.0639406375] | 11037 | 札幌市 | サッポロシ | Sapporo-shi | 東区 | ヒガシク | Higashi-ku | [141.363662, 43.076242] | NaN | NaN | NaN |
3 | 10006 | 北海道 | ホッカイドウ | Hokkaido | [141.347906782, 43.0639406375] | 11045 | 札幌市 | サッポロシ | Sapporo-shi | 白石区 | シロイシク | Shiroishi-ku | [141.396521, 43.045637] | NaN | NaN | NaN |
4 | 10006 | 北海道 | ホッカイドウ | Hokkaido | [141.347906782, 43.0639406375] | 11053 | 札幌市 | サッポロシ | Sapporo-shi | 豊平区 | トヨヒラク | Toyohira-ku | [141.379974, 43.03137] | NaN | NaN | NaN |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
1893 | 470007 | 沖縄県 | オキナワケン | Okinawa | [127.680975, 26.212365] | 473618 | 久米島町 | クメジマチョウ | Kumejima-cho | NaN | NaN | NaN | [126.80502100000001, 26.340669] | 島尻郡 | シマジリグン | Shimajiri-gun |
1894 | 470007 | 沖縄県 | オキナワケン | Okinawa | [127.680975, 26.212365] | 473626 | 八重瀬町 | ヤエセチョウ | Yaese-cho | NaN | NaN | NaN | [127.71864500000001, 26.158192] | 島尻郡 | シマジリグン | Shimajiri-gun |
1895 | 470007 | 沖縄県 | オキナワケン | Okinawa | [127.680975, 26.212365] | 473758 | 多良間村 | タラマソン | Tarama-son | NaN | NaN | NaN | [124.701693, 24.669449] | 宮古郡 | ミヤコグン | Miyako-gun |
1896 | 470007 | 沖縄県 | オキナワケン | Okinawa | [127.680975, 26.212365] | 473812 | 竹富町 | タケトミチョウ | Taketomi-cho | NaN | NaN | NaN | [124.154437, 24.339763] | 八重山郡 | ヤエヤマグン | Yaeyama-gun |
1897 | 470007 | 沖縄県 | オキナワケン | Okinawa | [127.680975, 26.212365] | 473821 | 与那国町 | ヨナグニチョウ | Yonaguni-cho | NaN | NaN | NaN | [123.004496, 24.468034] | 八重山郡 | ヤエヤマグン | Yaeyama-gun |
1898 rows × 16 columns
index_name = "japanese-addresses-v2"
payload = {
"mappings": {
"dynamic_templates": [
{
"code": {
"mapping": {
"type": "keyword"
},
"match_mapping_type": "string",
"path_match": "*_code"
}
},
{
"point": {
"mapping": {
"type": "geo_point"
},
"match_mapping_type": "string",
"path_match": "*_point"
}
},
{
"name_kana_and_kanji": {
"mapping": {
"type": "completion",
"analyzer": "kuromoji_completion_index",
"search_analyzer": "kuromoji_completion_query",
"preserve_separators": False,
"preserve_position_increments": True,
"max_input_length": 20,
"fields": {
"keyword": {
"type": "keyword"
},
"text": {
"type": "text",
"analyzer": "sudachi"
},
}
},
"match_mapping_type": "string",
"match_pattern": "regex",
"match": ".+_name_(kana|kanji)"
}
},
{
"name_romaji": {
"mapping": {
"type": "completion",
"analyzer": "kuromoji_completion_index",
"search_analyzer": "kuromoji_completion_query",
"preserve_separators": False,
"preserve_position_increments": True,
"max_input_length": 20,
"fields": {
"keyword": {
"type": "keyword"
},
"text": {
"type": "text",
"analyzer": "standard"
}
}
},
"match_mapping_type": "string",
"path_match": "*_name_romaji"
}
}
]
},
"settings": {
"index.number_of_shards": 1,
"index.number_of_replicas": 0,
"index.refresh_interval": -1,
"analysis": {
"analyzer": {
"kuromoji_completion_index": {
"mode": "index",
"type": "kuromoji_completion"
},
"kuromoji_completion_query": {
"mode": "query",
"type": "kuromoji_completion"
}
}
}
}
}
try:
# 既に同名のインデックスが存在する場合、いったん削除を行う
print("# delete index")
response = opensearch_client.indices.delete(index=index_name)
print(json.dumps(response, indent=2))
except Exception as e:
print(e)
response = opensearch_client.indices.create(index_name, body=payload)
response
# delete index NotFoundError(404, 'index_not_found_exception', 'no such index [japanese-addresses-v2]', japanese-addresses-v2, index_or_alias)
{'acknowledged': True, 'shards_acknowledged': True, 'index': 'japanese-addresses-v2'}
ドキュメントのロードを行います。ドキュメントのロードは bulk API を使用することで効率よく進められますが、データ処理フレームワークを利用することでより簡単にデータを取り込むことも可能です。本ワークショップでは、AWS SDK for Pandas を使用したデータ取り込みを行います。
index_name = "japanese-addresses-v2"
response = wr.opensearch.index_df(
client=opensearch_client,
df=japanese_addresses_v2_df,
use_threads=True,
id_keys=["city_code"],
index=index_name,
bulk_size=1000,
refresh=False
)
response["success"] の値が DataFrame の件数と一致しているかを確認します。True が表示される場合は全件登録に成功していると判断できます。
response["success"] == japanese_addresses_v2_df["pref_code"].count()
True
本ラボではデータ登録時に意図的に Refresh オプションを無効化しているため、念のため Refresh API を実行し、登録されたドキュメントが確実に検索可能となるようにします
index_name = "japanese-addresses-v2"
response = opensearch_client.indices.refresh(index=index_name)
response = opensearch_client.indices.forcemerge(index=index_name)
幾つかの候補クエリを用いてタ行の県の覧を取得します。各町ごとに県名を持っているため、サジェスト結果の重複を防ぐために skip_duplicates
パラメーターをセットしています。
index_name = "japanese-addresses-v2"
payload = {
"suggest": {
"suggest": {
"prefix": "t",
"completion": {
"field": "pref_name_kanji",
"skip_duplicates": True,
"size": 10
}
}
}
}
try:
response = opensearch_client.search(
index=index_name,
body=payload
)
except Exception as e:
print(e)
df = pd.json_normalize(response["suggest"]["suggest"]).explode("options")
pd.json_normalize(df["options"])
text | _index | _id | _score | _source.pref_code | _source.pref_name_kanji | _source.pref_name_kana | _source.pref_name_romaji | _source.pref_point | _source.city_code | _source.city_name_kanji | _source.city_name_kana | _source.city_name_romaji | _source.ward_name_kanji | _source.ward_name_kana | _source.ward_name_romaji | _source.city_point | _source.county_name_kanji | _source.county_name_kana | _source.county_name_romaji | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 千葉県 | japanese-addresses-v2 | 121011 | 1.0 | 120006 | 千葉県 | チバケン | Chiba | [140.123184, 35.604588] | 121011 | 千葉市 | チバシ | Chiba-shi | 中央区 | チュウオウク | Chuo-ku | [140.122853, 35.60741300000001] | NaN | NaN | NaN |
1 | 富山県 | japanese-addresses-v2 | 162108 | 1.0 | 160008 | 富山県 | トヤマケン | Toyama | [137.211341, 36.69519] | 162108 | 南砺市 | ナントシ | Nanto-shi | NaN | NaN | NaN | [136.875395, 36.557451] | NaN | NaN | NaN |
2 | 徳島県 | japanese-addresses-v2 | 362018 | 1.0 | 360007 | 徳島県 | トクシマケン | Tokushima | [134.559484, 34.065728] | 362018 | 徳島市 | トクシマシ | Tokushima-shi | NaN | NaN | NaN | [134.554713, 34.070234] | NaN | NaN | NaN |
3 | 東京都 | japanese-addresses-v2 | 133051 | 1.0 | 130001 | 東京都 | トウキョウト | Tokyo | [139.691717, 35.689568] | 133051 | 日の出町 | ヒノデマチ | Hinode-machi | NaN | NaN | NaN | [139.257405, 35.742115] | 西多摩郡 | ニシタマグン | Nishitama-gun |
4 | 栃木県 | japanese-addresses-v2 | 92011 | 1.0 | 90000 | 栃木県 | トチギケン | Tochigi | [139.883528, 36.565689] | 92011 | 宇都宮市 | ウツノミヤシ | Utsunomiya-shi | NaN | NaN | NaN | [139.882807, 36.555115] | NaN | NaN | NaN |
5 | 鳥取県 | japanese-addresses-v2 | 312011 | 1.0 | 310000 | 鳥取県 | トットリケン | Tottori | [134.238174, 35.503704] | 312011 | 鳥取市 | トットリシ | Tottori-shi | NaN | NaN | NaN | [134.222122, 35.494395] | NaN | NaN | NaN |
index_name = "japanese-addresses-v2"
payload = {
"suggest": {
"suggest": {
"prefix": "と",
"completion": {
"field": "pref_name_kanji",
"skip_duplicates": True,
"size": 10
}
}
}
}
try:
response = opensearch_client.search(
index=index_name,
body=payload
)
except Exception as e:
print(e)
df = pd.json_normalize(response["suggest"]["suggest"]).explode("options")
pd.json_normalize(df["options"])
text | _index | _id | _score | _source.pref_code | _source.pref_name_kanji | _source.pref_name_kana | _source.pref_name_romaji | _source.pref_point | _source.city_code | _source.city_name_kanji | _source.city_name_kana | _source.city_name_romaji | _source.city_point | _source.county_name_kanji | _source.county_name_kana | _source.county_name_romaji | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 富山県 | japanese-addresses-v2 | 162108 | 1.0 | 160008 | 富山県 | トヤマケン | Toyama | [137.211341, 36.69519] | 162108 | 南砺市 | ナントシ | Nanto-shi | [136.875395, 36.557451] | NaN | NaN | NaN |
1 | 徳島県 | japanese-addresses-v2 | 362018 | 1.0 | 360007 | 徳島県 | トクシマケン | Tokushima | [134.559484, 34.065728] | 362018 | 徳島市 | トクシマシ | Tokushima-shi | [134.554713, 34.070234] | NaN | NaN | NaN |
2 | 東京都 | japanese-addresses-v2 | 133051 | 1.0 | 130001 | 東京都 | トウキョウト | Tokyo | [139.691717, 35.689568] | 133051 | 日の出町 | ヒノデマチ | Hinode-machi | [139.257405, 35.742115] | 西多摩郡 | ニシタマグン | Nishitama-gun |
3 | 栃木県 | japanese-addresses-v2 | 92011 | 1.0 | 90000 | 栃木県 | トチギケン | Tochigi | [139.883528, 36.565689] | 92011 | 宇都宮市 | ウツノミヤシ | Utsunomiya-shi | [139.882807, 36.555115] | NaN | NaN | NaN |
4 | 鳥取県 | japanese-addresses-v2 | 312011 | 1.0 | 310000 | 鳥取県 | トットリケン | Tottori | [134.238174, 35.503704] | 312011 | 鳥取市 | トットリシ | Tottori-shi | [134.222122, 35.494395] | NaN | NaN | NaN |
index_name = "japanese-addresses-v2"
payload = {
"suggest": {
"suggest": {
"prefix": "とy",
"completion": {
"field": "pref_name_kanji",
"skip_duplicates": True,
"size": 10
}
}
}
}
try:
response = opensearch_client.search(
index=index_name,
body=payload
)
except Exception as e:
print(e)
df = pd.json_normalize(response["suggest"]["suggest"]).explode("options")
pd.json_normalize(df["options"])
text | _index | _id | _score | _source.pref_code | _source.pref_name_kanji | _source.pref_name_kana | _source.pref_name_romaji | _source.pref_point | _source.city_code | _source.city_name_kanji | _source.city_name_kana | _source.city_name_romaji | _source.city_point | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 富山県 | japanese-addresses-v2 | 162108 | 1.0 | 160008 | 富山県 | トヤマケン | Toyama | [137.211341, 36.69519] | 162108 | 南砺市 | ナントシ | Nanto-shi | [136.875395, 36.557451] |
漢字のフィールドに対してなぜ "とy" といった文字列で入力補完が成立するのでしょうか。 completion フィールドタイプによるオートコンプリートでは、ドキュメントからアナライザーによって生成されたトークンを格納しておき、検索時に入力クエリから生成されたトークンと前方一致および正規表現によるマッチングを行います。
以下は富山県を入力用のアナライザーで処理した結果です。
index_name = "japanese-addresses-v2"
payload = {
"text": "富山県",
"analyzer": "kuromoji_completion_index"
}
try:
response = opensearch_client.indices.analyze(
index=index_name,
body=payload
)
except Exception as e:
print(e)
pd.json_normalize(response["tokens"])
token | start_offset | end_offset | type | position | |
---|---|---|---|---|---|
0 | 富山 | 0 | 2 | word | 0 |
1 | toyama | 0 | 2 | word | 0 |
2 | 県 | 2 | 3 | word | 1 |
3 | ken | 2 | 3 | word | 1 |
4 | kenn | 2 | 3 | word | 1 |
以下は検索用のクエリを検索用のアナライザーで処理した結果です。
index_name = "japanese-addresses-v2"
payload = {
"text": "とy",
"analyzer": "kuromoji_completion_query"
}
try:
response = opensearch_client.indices.analyze(
index=index_name,
body=payload
)
except Exception as e:
print(e)
pd.json_normalize(response["tokens"])
token | start_offset | end_offset | type | position | |
---|---|---|---|---|---|
0 | とy | 0 | 2 | word | 0 |
1 | toy | 0 | 2 | word | 0 |
データ格納時に生成された "toyama" と検索時に生成された "toy" が前方一致によりマッチングされたため、サジェストの結果として現れたということが確認できます。
前方一致ではなく正規表現を使用する場合は、suggest API に regex 要素を指定します
index_name = "japanese-addresses-v2"
payload = {
"suggest": {
"suggest": {
"regex": ".*shima.*",
"completion": {
"field": "pref_name_kana",
"skip_duplicates": True,
"size": 10
}
}
},
"profile": True
}
try:
response = opensearch_client.search(
index=index_name,
body=payload
)
except Exception as e:
print(e)
df = pd.json_normalize(response["suggest"]["suggest"]).explode("options")
pd.json_normalize(df["options"])
text | _index | _id | _score | _source.pref_code | _source.pref_name_kanji | _source.pref_name_kana | _source.pref_name_romaji | _source.pref_point | _source.city_code | _source.city_name_kanji | _source.city_name_kana | _source.city_name_romaji | _source.city_point | _source.ward_name_kanji | _source.ward_name_kana | _source.ward_name_romaji | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | カゴシマケン | japanese-addresses-v2 | 462012 | 1.0 | 460001 | 鹿児島県 | カゴシマケン | Kagoshima | [130.558141, 31.560185000000004] | 462012 | 鹿児島市 | カゴシマシ | Kagoshima-shi | [130.557339, 31.596789] | NaN | NaN | NaN |
1 | シマネケン | japanese-addresses-v2 | 322016 | 1.0 | 320005 | 島根県 | シマネケン | Shimane | [133.05053, 35.472212] | 322016 | 松江市 | マツエシ | Matsue-shi | [133.04852700000004, 35.468039] | NaN | NaN | NaN |
2 | トクシマケン | japanese-addresses-v2 | 362018 | 1.0 | 360007 | 徳島県 | トクシマケン | Tokushima | [134.559484, 34.065728] | 362018 | 徳島市 | トクシマシ | Tokushima-shi | [134.554713, 34.070234] | NaN | NaN | NaN |
3 | ヒロシマケン | japanese-addresses-v2 | 341011 | 1.0 | 340006 | 広島県 | ヒロシマケン | Hiroshima | [132.459369, 34.396271] | 341011 | 広島市 | ヒロシマシ | Hiroshima-shi | [132.454992, 34.386288] | 中区 | ナカク | Naka-ku |
4 | フクシマケン | japanese-addresses-v2 | 72010 | 1.0 | 70009 | 福島県 | フクシマケン | Fukushima | [140.467734, 37.749957] | 72010 | 福島市 | フクシマシ | Fukushima-shi | [140.473269, 37.760759] | NaN | NaN | NaN |
東御市(とうみし) のような難読地名については、漢字のフィールドに対して Kuromoji が正しく読み仮名を解釈できない可能性があります。以下は一例です。
index_name = "japanese-addresses-v2"
payload = {
"text": "東御市",
"analyzer": "kuromoji_completion_index"
}
try:
response = opensearch_client.indices.analyze(
index=index_name,
body=payload
)
except Exception as e:
print(e)
pd.json_normalize(response["tokens"])
token | start_offset | end_offset | type | position | |
---|---|---|---|---|---|
0 | 東 | 0 | 1 | word | 0 |
1 | higasi | 0 | 1 | word | 0 |
2 | higashi | 0 | 1 | word | 0 |
3 | 御 | 1 | 2 | word | 1 |
4 | go | 1 | 2 | word | 1 |
5 | 市 | 2 | 3 | word | 2 |
6 | si | 2 | 3 | word | 2 |
7 | shi | 2 | 3 | word | 2 |
index_name = "japanese-addresses-v2"
payload = {
"suggest": {
"suggest": {
"prefix": "toumi",
"completion": {
"field": "city_name_kanji"
}
}
}
}
try:
response = opensearch_client.search(
index=index_name,
body=payload
)
except Exception as e:
print(e)
response
{'took': 1, 'timed_out': False, '_shards': {'total': 1, 'successful': 1, 'skipped': 0, 'failed': 0}, 'hits': {'total': {'value': 0, 'relation': 'eq'}, 'max_score': None, 'hits': []}, 'suggest': {'suggest': [{'text': 'toumi', 'offset': 0, 'length': 5, 'options': []}]}}
こういったケースでは Kuromoji Completion がインデクシング時に正しく東御市を "トウミシ" と解釈できるようにカスタム辞書をセットするのも手ではありますが、カスタム辞書を更新するたびに reindex が必要となります。代替アプローチとして本データセットのように、カナをあらかじめデータの方にセットしておき、カナフィールドでオートコンプリートを実行する方法もあります。
index_name = "japanese-addresses-v2"
payload = {
"suggest": {
"suggest": {
"prefix": "toumi",
"completion": {
"field": "city_name_kana"
}
}
}
}
try:
response = opensearch_client.search(
index=index_name,
body=payload
)
except Exception as e:
print(e)
df = pd.json_normalize(response["suggest"]["suggest"]).explode("options")
pd.json_normalize(df["options"])
text | _index | _id | _score | _source.pref_code | _source.pref_name_kanji | _source.pref_name_kana | _source.pref_name_romaji | _source.pref_point | _source.city_code | _source.city_name_kanji | _source.city_name_kana | _source.city_name_romaji | _source.city_point | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | トウミシ | japanese-addresses-v2 | 202193 | 1.0 | 200000 | 長野県 | ナガノケン | Nagano | [138.180991, 36.65131] | 202193 | 東御市 | トウミシ | Tomi-shi | [138.330295, 36.35955] |
漢字を使ったサジェストも可能です
index_name = "japanese-addresses-v2"
payload = {
"suggest": {
"suggest": {
"prefix": "東",
"completion": {
"field": "city_name_kanji"
}
}
}
}
try:
response = opensearch_client.search(
index=index_name,
body=payload
)
except Exception as e:
print(e)
df = pd.json_normalize(response["suggest"]["suggest"]).explode("options")
pd.json_normalize(df["options"])
text | _index | _id | _score | _source.pref_code | _source.pref_name_kanji | _source.pref_name_kana | _source.pref_name_romaji | _source.pref_point | _source.city_code | _source.city_name_kanji | _source.city_name_kana | _source.city_name_romaji | _source.city_point | _source.county_name_kanji | _source.county_name_kana | _source.county_name_romaji | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 東伊豆町 | japanese-addresses-v2 | 223018 | 1.0 | 220001 | 静岡県 | シズオカケン | Shizuoka | [138.383023, 34.976906] | 223018 | 東伊豆町 | ヒガシイズチョウ | Higashiizu-cho | [139.041265, 34.772816000000006] | 賀茂郡 | カモグン | Kamo-gun |
1 | 東吾妻町 | japanese-addresses-v2 | 104299 | 1.0 | 100005 | 群馬県 | グンマケン | Gumma | [139.060947, 36.391192] | 104299 | 東吾妻町 | ヒガシアガツママチ | Higashiagatsuma-machi | [138.820512, 36.571557] | 吾妻郡 | アガツマグン | Agatsuma-gun |
2 | 東川町 | japanese-addresses-v2 | 14583 | 1.0 | 10006 | 北海道 | ホッカイドウ | Hokkaido | [141.347906782, 43.0639406375] | 14583 | 東川町 | ヒガシカワチョウ | Higashikawa-cho | [142.510128, 43.698877] | 上川郡 | カミカワグン | Kamikawa-gun |
3 | 東広島市 | japanese-addresses-v2 | 342122 | 1.0 | 340006 | 広島県 | ヒロシマケン | Hiroshima | [132.459369, 34.396271] | 342122 | 東広島市 | ヒガシヒロシマシ | Higashihiroshima-shi | [132.743746, 34.426787000000004] | NaN | NaN | NaN |
4 | 東御市 | japanese-addresses-v2 | 202193 | 1.0 | 200000 | 長野県 | ナガノケン | Nagano | [138.180991, 36.65131] | 202193 | 東御市 | トウミシ | Tomi-shi | [138.330295, 36.35955] | NaN | NaN | NaN |
本ラボでは、Kuromoji completion を使用したサジェスタの実装について学習しました。
本ワークショップで使用したインデックスを削除します。インデックスの削除は Delete index API で行います。インデックスを削除するとインデックス内のドキュメントも削除されます。
index_name = "japanese-addresses-v2"
try:
response = opensearch_client.indices.delete(index=index_name)
print(json.dumps(response, indent=2))
except Exception as e:
print(e)
{ "acknowledged": true }
ダウンロードしたデータセットを削除します。./dataset ディレクトリ配下に何もない場合は、./dataset ディレクトリも合わせて削除します。
%rm -rf {dataset_dir}
%rmdir ./dataset