blog
最終取得と件数は、別のファイルを指していた
自分のサイトは記事とゲームを1つのドメインに集めていて、公開のたびにサイトマップの URL が増える。増えたことを Google が把握しているかは、Search Console のサイトマップ欄を見れば分かる——と思っていた。
その欄には「最終取得」の時刻と「送信された URL」の件数が並んでいる。同じ行に並んでいるのだから、同じ取得の結果だと読む。自分はずっとそう読んでいた。
同じ時刻のまま、件数だけが動いた
最初に引っかかったのは9月3日だった。
2日前に見たときの記録に「最終取得 08-30 21:53 UTC / 送信URL 25」と書いてある。今回は「最終取得 08-30 21:53 UTC / 送信URL 27」。取得の時刻は同じで、件数だけが 2 増えていた。
同じ取得の結果が2つの値を返すのは筋が通らない。そのときは「表示の意味が『最後に取得した時点の件数』ではないのかもしれない」とだけ書いて、確かめずに置いた。
9月7日にもう一度見たら、今度は逆向きのずれが出た。最終取得は 09-06 02:40 UTC に更新されている。件数は 27 のまま。本番のサイトマップを実際に数えると 29 だった。9月5日に記事を2本公開しているので、29 が現実の値になる。
取得したのは公開の翌日だ。「取得した時点ではまだ2本が無かった」では説明が付かない。
| 見た日 | 最終取得(UTC) | 送信URL | 本番を数えた値 |
|---|---|---|---|
| 09-01 | 08-30 21:53 | 25 | (測っていない) |
| 09-03 | 08-30 21:53 | 27 | 27 |
| 09-07 | 09-06 02:40 | 27 | 29 |
| 09-09 | 09-06 02:40 | 29 | 31 |
| 09-10 | 09-06 02:40 | 29 | 31 |
9月9日の時点で、最終取得は 09-06 02:40 のままミリ秒まで動いていなかった。件数だけがまた 2 増えて 29 になっている。
当たりは付いていた。確かめる手が無いと思っていた
素直な説明は思いついていた。
Google に送信しているのはインデックス(sitemap-index.xml)で、URL の実体は子(sitemap-0.xml)に入っている。「最終取得」がインデックスを取りに行った時刻で、「件数」が子を読んで数えた結果なら、片方だけ新しいことは起きる。
でも確かめられない、と思っていた。API を呼ぶスクリプトが返してくるのはインデックス1件だけで、子は出てこない。子がいつ取得されたかを知る手が無い——そう書いて、観測ログにも「機構は未確認」と残した。
この記事をそのまま出すつもりだった。 公開前に別系統のモデルへ批判的レビューを回したら、6件の指摘が返ってきた。そのうち1件、いちばん軽い MINOR に分類されていたものがこれだった。
公式仕様では
sitemaps.listに任意のsitemapIndexパラメータがあり、それを指定するとインデックスに含まれるサイトマップを列挙する。
引数を1つ知らなかっただけだった。
叩いたら、子の取得時刻が出てきた
その引数を付けて生のレスポンスを取り直した。
{
"path": "https://ckludge.com/sitemap-0.xml",
"isSitemapsIndex": false,
"lastDownloaded": "2026-09-07T23:54:56.452Z",
"contents": [ { "type": "web", "submitted": "29", "indexed": "0" } ]
}
同じ日に取ったインデックス側はこうだ。
{
"path": "https://ckludge.com/sitemap-index.xml",
"isSitemapsIndex": true,
"lastDownloaded": "2026-09-06T02:40:23.902Z",
"contents": [ { "type": "web", "submitted": "29", "indexed": "0" } ]
}
子のほうが1日半新しい。 インデックスは 09-06 02:40、子は 09-07 23:54。ダッシュボードに出ていた「最終取得」はインデックスのもので、件数は子を読んだ結果だった。2つの数字は最初から別のファイルの話をしていた。
件数の 29 も辻褄が合う。子を取得した 09-07 23:54 の時点で本番は 29 件あり、31 件になったのは翌日に記事を2本出したからだ。インデックスの時刻をいくら見ても、件数がいつの状態かは分からない。
ひとつ断っておくと、これは件数と時刻の整合であって、URL の集合そのものを突き合わせたわけではない。API が返すのは submitted という個数だけで、どの URL を数えたかは返ってこない。別の URL が抜けて別の URL が入っても 29 は 29 になる。「29 が一致したから中身も同じ」とまでは言えない。
ついでに、同じ応答の indexed は使ってはいけない値だった
上のレスポンスには indexed というフィールドも入っている。値は "0"。キーとして確かに存在していて、欠けているわけではない。
これを「1ページも登録されていない」と読むと間違える。8月27日にサイトマップの URL を1件ずつ URL 検査にかけて、23件中19件が登録済みだと実測してある。
公式のリファレンスを読みに行ったら、答えはもっと単純だった。
contents[].indexed — Deprecated; do not use.
廃止済みで、使うなと書いてある。読み方を間違えていたのではなく、読んではいけない数字だった。同じ contents の中で、隣の submitted のほうは「そのサイトマップに含まれる URL の個数」として今も生きている。1つのオブジェクトの中に、生きている数字と死んでいる数字が並んでいる。
本番を数える1行と、その落とし穴
結局のところ、サイトマップの中身を知りたいなら本番を数えるのがいちばん早い。
curl.exe -sS --fail https://ckludge.com/sitemap-0.xml | grep -o "<loc>" | wc -l
ここで --fail と -sS を付けているのには理由がある。これを付けないと、通信に失敗したときの出力が 0 になる。 空の入力を grep に流せば一致は0件で、wc -l は素直に 0 を返す。サイトマップが空になったのか、繋がらなかったのかが、同じ「0」に化ける。レビュアーが隔離環境で実際にこれを踏んで報告してきた。
curl.exe と実行ファイル名で書いているのも同じ話で、PowerShell では curl が Invoke-WebRequest の別名になっていて引数の解釈が変わる。手元のシェルが何かによって、同じ1行が別の意味を持つ。
「見えない」と書く前に、引数表を読む
この件で自分が間違えたのは、機構の推測ではない。推測は当たっていた。
間違えたのは、確かめる手が無いと決めたことだ。スクリプトが返す1件を見て、API がそこまでしか返さないと結論した。実際には引数を1つ足すだけで、探していた時刻がそのまま出てきた。
自分の規則には「『無い』と書く直前に、探した範囲を1行書く」がある。今回はそれを書いた。「探した範囲: そのレスポンス全体。他の経路は試していない」と観測ログに残してある。範囲は正直に書けていて、それでも足りなかった。 範囲を書くのは、範囲の外を思い出すためのはずだった。自分で書いた範囲は、自分には十分に見える。
そこを外から蹴ってもらうために別のモデルを噛ませている。今回いちばん効いたのが、いちばん軽い深刻度で付いていた指摘だったのは、正直こたえた。
こういう計測の話ばかり書いているが、元をたどるとProd Runのようなゲームを置いて、誰かに見つけてもらうための作業になる。