Hugo에서 Sitemap-index 사용하기(split sitemap)

sitemap.xml

sitemap.xml은 Sitemap protocol을 위한 XML schema로 웹 서비스가 포함하고 있는 링크들을 사용자에게 제공하기 위한 목적으로 구성되는 파일입니다. 아래와 같은 구조를 가지며, 사용자나 검색 봇 등은 이 파일을 참조하여 웹 페이지를 수집합니다.

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
   <url>
      <loc>http://www.example.com/</loc>
      <lastmod>2005-01-01</lastmod>
      <changefreq>monthly</changefreq>
      <priority>0.8</priority>
   </url>
</urlset>

물론 무조건 sitemap.xml 이란 파일 이름으로 구성이 필요한건 아닙니다. Sitemap protocol에 준수되는 포맷이면 어떤 파일 이름이라도 상관없으며, 검색 봇들은 이를 찾기 위해 robots.txt를 조회하여 찾게 됩니다.

User-agent: *
Allow: /

Sitemap: https://www.hahwul.com/sitemap.xml

Big sitemap

때때로 서비스의 크기에 따라서 이 sitemap이 굉장히 커질 수도 있습니다. 물론 단순히 텍스트 파일이기 때문에 네트워크 트래픽 자체는 높지 않습니다만, 검색 봇들은 보통 sitemap의 크기를 제한하고 있어 큰 sitemap을 search console 과 같은 도구로 전달하게 되면 에러가 발생하는 경우가 많습니다.

구글 기준으론 하나의 sitemap.xml 파일의 최대 index의 수는 50k, 즉 50,000개 이상의 index를 가지는 파일은 처리하지 않는다고 합니다. 그래서 이를 해결하기 위해 sitemap-index 라는 방법을 제시하고 있습니다.

이는 하나의 sitemap 파일에 엔드포인트 링크를 담는 것이 아닌 추가적인 sitemap 파일을 담아서 50,000 이상의 sitemap을 읽을 수 있도록 하는 방법입니다.

<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <sitemap>
    <loc>http://www.example.com/sitemap1.xml.gz</loc>
  </sitemap>
  <sitemap>
    <loc>http://www.example.com/sitemap2.xml.gz</loc>
  </sitemap>
</sitemapindex>

이렇게 여러개로 나누어진 sitemap을 최종 sitemap에서 <sitemap> 을 통해 매핑해주면, 검색 봇은 모든 sitemap을 접근하여 페이지를 수집하게 됩니다. 이런 형태로 한다면 50k 이상의 sitemap도 등록이 가능합니다.

In Hugo?

그러면 hugo에서는 이 기능을 제공할까요? 안타깝게도 제가 찾아본 바로는 sitemap-index를 제공해주지 않습니다. 그래서 사용자가 직접 Go template 코드를 이용해 구현하거나 다른 3rd party 도구 또는 코드의 힘을 빌어 sitemap-index를 구현해야 합니다.

with Ruby!!

제가 지금은 거의 GO만 사용하곤 있지만 그래도 이렇게 특정 목적을 위한 단순한 스크립트는 ruby가 빠르고 편하기 때문에 ruby로 해결할 방법을 찾아봤습니다. 다행히 누군가 이를 고려해서 만들어둔 gem이 있네요!

gem install sitemap_generator

코드에서 사용 가능한 라이브러리로 아래와 같이 SitemapGenerator를 이용하여 sitemap 파일을 생성할 수 있습니다.

require 'rubygems'
require 'sitemap_generator'

SitemapGenerator::Sitemap.default_host = 'https://www.hahwul.com'

# create_index를 true로 전달해야 대용량 sitemap인 경우 분할하여 저장하게 됩니다.
SitemapGenerator::Sitemap.create_index = true
SitemapGenerator::Sitemap.create do
  add '/page1', :changefreq => 'daily', :priority => 0.9
  add '/page2', :changefreq => 'daily'
  add '/page3', :changefreq => 'daily'
  add '/page4', :changefreq => 'daily'
  add '/page5', :changefreq => 'daily'
  add '/page6', :changefreq => 'daily'      
end

주석에도 달아두었지만, Sitemap 분할을 위해선 SitemapGenerator::Sitemap.create_indextrue로 넘겨주어야 합니다. 저 상태로 코드를 실행해보면 sitemap.xml.gz 파일로 생성되는 것을 볼 수 있습니다. (만약 create_index가 빠지면 sitemap.xml 파일 하나만 생성됩니다 😁)

ruby make-sitemap.rb
In '/Users/hahwul/HAHWUL/tool/test/public/':
+ sitemap.xml.gz                                           7 links /  371 Bytes
Sitemap stats: 7 links / 1 sitemaps / 0m00s

ll public/
total 8
drwxr-xr-x  3 hahwul  staff   96  9 21 18:33 .
drwxr-xr-x  4 hahwul  staff  128  9 21 18:34 ..
-rw-r--r--  1 hahwul  staff  371  9 21 18:34 sitemap.xml.gz

압축을 풀어서 내용을 보면 크게 문제 없이 잘 구성되었네요 😍

<?xml version="1.0" encoding="UTF-8"?>
<urlset
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"
	xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
	xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"
	xmlns:video="http://www.google.com/schemas/sitemap-video/1.1"
	xmlns:news="http://www.google.com/schemas/sitemap-news/0.9"
	xmlns:mobile="http://www.google.com/schemas/sitemap-mobile/1.0"
	xmlns:pagemap="http://www.google.com/schemas/sitemap-pagemap/1.0"
	xmlns:xhtml="http://www.w3.org/1999/xhtml">
	<url>
		<loc>https://www.hahwul.com</loc>
		<lastmod>2021-09-21T18:39:00+09:00</lastmod>
		<changefreq>always</changefreq>
		<priority>1.0</priority>
	</url>
	<url>
		<loc>https://www.hahwul.com/page1</loc>
		<lastmod>2021-09-21T18:39:00+09:00</lastmod>
		<changefreq>daily</changefreq>
		<priority>0.9</priority>
	</url>
	<url>
		<loc>https://www.hahwul.com/page2</loc>
		<lastmod>2021-09-21T18:39:00+09:00</lastmod>
		<changefreq>daily</changefreq>
		<priority>0.5</priority>
	</url>
	<url>
		<loc>https://www.hahwul.com/page3</loc>
		<lastmod>2021-09-21T18:39:00+09:00</lastmod>
		<changefreq>daily</changefreq>
		<priority>0.5</priority>
	</url>
	<url>
		<loc>https://www.hahwul.com/page4</loc>
		<lastmod>2021-09-21T18:39:00+09:00</lastmod>
		<changefreq>daily</changefreq>
		<priority>0.5</priority>
	</url>
	<url>
		<loc>https://www.hahwul.com/page5</loc>
		<lastmod>2021-09-21T18:39:00+09:00</lastmod>
		<changefreq>daily</changefreq>
		<priority>0.5</priority>
	</url>
	<url>
		<loc>https://www.hahwul.com/page6</loc>
		<lastmod>2021-09-21T18:39:00+09:00</lastmod>
		<changefreq>daily</changefreq>
		<priority>0.5</priority>
	</url>
</urlset>

Ruby + Hugo

자 그럼 Hugo 사이트에 이를 적용하기 위해선 어떻게 해야할까요? 우선 hugo에서 기본으로 생성해주는 sitemap을 파싱하거나, url 리스트를 별도로 뽑아내야 합니다. 그리고 이를 기반으로 루프를 돌려 index를 추가하면 됩니다.

# Make sitemap
SitemapGenerator::Sitemap.default_host = 'https://********.hahwul.com'
SitemapGenerator::Sitemap.create do
  uris.each do |u|
    add "#{u.downcase}", :changefreq => 'daily'
  end
end

그러고 테스트 해보면 50k 단위로 잘려서 여러개의 파일이 생성된 것으로 확인할 수 있습니다.

+ sitemap1.xml.gz                                      50000 links /    27.5 KB
+ sitemap2.xml.gz                                      50000 links /    27.5 KB
+ sitemap3.xml.gz                                      50000 links /    27.5 KB
+ sitemap4.xml.gz                                      17973 links /    10.1 KB
+ sitemap.xml.gz                                        4 sitemaps /  256 Bytes
Sitemap stats: 167,973 links / 4 sitemaps / 0m11s
Count: 212074
...

sitemap.xml.gz 을 풀어보면 아래와 같이 1~4까지의 xml을 바라보고 있구요.

<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/siteindex.xsd"
	xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
	<sitemap>
		<loc>https://********.hahwul.com/sitemap1.xml.gz</loc>
		<lastmod>2021-09-21T21:41:05+09:00</lastmod>
	</sitemap>
	<sitemap>
		<loc>https://********.hahwul.com/sitemap2.xml.gz</loc>
		<lastmod>2021-09-21T21:41:05+09:00</lastmod>
	</sitemap>
	<sitemap>
		<loc>https://********.hahwul.com/sitemap3.xml.gz</loc>
		<lastmod>2021-09-21T21:41:09+09:00</lastmod>
	</sitemap>
	<sitemap>
		<loc>https://********.hahwul.com/sitemap4.xml.gz</loc>
		<lastmod>2021-09-21T21:41:10+09:00</lastmod>
	</sitemap>
</sitemapindex>

구글 서치 콘솔에서도 잘 읽힙니다 😍

References

  • https://developers.google.com/search/docs/advanced/sitemaps/build-sitemap
  • https://developers.google.com/search/docs/advanced/sitemaps/large-sitemaps
  • https://github.com/kjvarga/sitemap_generator