同じURLを読み戻しただけで、検索条件が2件減った。
検索APIのクエリでは、キーと値の組を最後まで残したい。辞書にすると複数指定がつぶれる。空文字も読み取り時に消えるんだよね。
今日、5組の条件をURLへ変換し、読み戻して比べた。例外は出ないのに、タグが一つと空の条件が欠けた。LLMの検索ツールでこれが起きると、回答だけ見て原因を追うのは難しい。
検索APIのクエリで、どの2件が消えるか
今回扱うのは、tag=Python&tag=LLMのように同じキーを繰り返す形式。入力は次の5組にした。
| キー | 値 | 残したい内容 |
|---|---|---|
q |
A+B C |
プラス記号と空白を含む検索語 |
tag |
Python |
一つ目のタグ |
tag |
LLM |
二つ目のタグ |
owner |
空文字 | 空値を明示した指定 |
limit |
0 |
文字列のゼロ |
空値や複数タグの意味はAPIごとの仕様だ。ここでは5組を変えずに送信できるかを調べる。検索結果は測っていない。
CPython 3.14.6、macOSで実行済み。標準ライブラリのみ、外部通信なし。query_roundtrip.pyに保存し、python3 query_roundtrip.pyで動く。
from collections import Counter
from urllib.parse import parse_qsl, urlencode
expected = [
('q', 'A+B C'),
('tag', 'Python'),
('tag', 'LLM'),
('owner', ''),
('limit', '0'),
]
query = urlencode(expected)
before = list(dict(parse_qsl(query)).items())
after = parse_qsl(query, keep_blank_values=True)
def missing(actual):
return sum((Counter(expected) - Counter(actual)).values())
print(query)
print('before:', before)
print('after:', after)
print(f'欠落: {missing(before)} -> {missing(after)}')
assert missing(before) == 2
assert after == expected
出力はこうなった。
q=A%2BB+C&tag=Python&tag=LLM&owner=&limit=0
before: [('q', 'A+B C'), ('tag', 'LLM'), ('limit', '0')]
after: [('q', 'A+B C'), ('tag', 'Python'), ('tag', 'LLM'), ('owner', ''), ('limit', '0')]
欠落: 2 -> 0
生成したクエリには、まだ5組とも入っている。
owner=が落ち、続くdict()でtag=Pythonが上書きされる。LLMは残っているので、タグ名だけ眺めると気づきにくい。
Counterの差で欠けた組を数える。追加や順序の違いは数字に出ない。assert after == expectedで、余分な組がなく、順序も一致することまで確かめた。
urllib.parseの中で起きていること
手元のurllib.parseのソースとdocstringも確認した。parse_qsl()は、既定のkeep_blank_values=Falseでは空値を含めない。空値を残す処理では、ここを明示する。
返り値はタプルのリストなので、同じキーを何度でも持てる。辞書へ詰め直すと、キー一つにつき後の値だけが残る。
parse_qs()なら、同じキーの値をリストにまとめてくれる。今回のように並びごと照合するなら、parse_qsl()のままが扱いやすい。
出力のA%2BB+Cでは、プラス記号が%2B、空白が+になった。この組み合わせなら元へ戻る。手書きでq=A+Bを作ると、読み戻した検索語はA Bだった。プラス記号を探す検索で、この差は痛い。
このくらいのURLでも、ログを目で追うのは面倒だな。
API連携へ持ち込む前に
この手順は、同じキーを繰り返して受け取るAPIで使える。配列をカンマ区切りやJSONで送るAPIには、その仕様に合わせた変換が要る。URLへ載せられても、複数タグの検索が成立したかは別に確かめたい。
自分は検索ツールを足すとき、複数値と空文字を含む条件を一度読み戻して照合する。今回の5組では、欠落2件を0件にできた。実際の連携では、API側の絞り込み結果も確認する。検索ツールが増えるほど、条件を辞書へ詰め直す小さな処理が、調査の手間を増やすと見ている。