はじめに# IIIF (International Image Interoperability Framework) は、デジタルアーカイブや美術館のコレクションで広く使われている画像配信の国際規格です。IIIF Content Search API を使うと、マニフェスト内のアノテーション(注釈やタグ)を検索できます。
しかし、IIIF Content Search API は通常、サーバーサイドでの実装が前提となっており、静的サイト(GitHub Pages、Vercel、Netlify など)では実現が難しいとされてきました。
本記事では、Service Worker を使ってクライアントサイドで IIIF Content Search API を実装する方法 を紹介します。この手法により、静的サイトでも Mirador などの IIIF ビューアで検索機能を利用できるようになります。
従来のIIIF Search APIの仕組み# [ M i r a d o r ] → G E T / s e a r c h ? q = k e y w o r d → [ サ ー バ ー ] → 検 索 処 理 → J S O N 応 答
IIIF Content Search API は、クエリパラメータ(?q=検索語)を受け取り、検索結果を JSON で返すエンドポイントを必要とします。これは動的なサーバー処理を前提としています。
静的サイトの制約# 静的サイトでは:
クエリパラメータに応じた動的なレスポンスを返せない サーバーサイドの検索処理を実行できない 静的 JSON ファイルしか配信できない 解決策:Service Worker によるリクエストインターセプト# Service Worker は、ブラウザとネットワークの間に位置するプロキシとして機能します。これを活用して、検索リクエストをインターセプトし、クライアントサイドで検索処理を行います。
アーキテクチャ# [ [ [ M S M i e i r r r a │ │ ↓ v │ ├ │ ├ │ └ ↓ a d i ─ ─ ─ d o G c o r E e 静 J I r ] T 的 a I ] W な v I / o a F ← i r i S i k n c C 検 i e d r o 索 f r e i n 結 / ] x p t 果 s . t e を i ← j n 表 t s で t 示 e イ o 検 / ン n 索 S s タ を e e ー を 実 a a セ 行 r r プ f c c ト e h h t / c A i h P n ( I d 初 e 回 形 x の 式 . み で j ) 応 s 答 o n ? q = k e y w o r d
1. 検索インデックスの生成(ビルド時)# まず、アノテーションデータから検索インデックスを生成します。
f } u n c a } r } b c o n ) e ; u t n n e } ; t ' t t e i i s o n ) u @ y o n l o t t t t l m a c m t ; r c p t t d n a r e a o n a a a n o e a r - e t i x n t n n n r ? : n : l i s g n i e t g i o v i g { t E e e e t o s : u v t a f e ` c e ' n s a n r n . a a a s e t $ a x S t r e i s p a g t t I s : { n t e r c r e . u n e i i d t c v ' a i h a s f s n : o o : I a a a : r e - t o h o n n d n n s c s i e = r ( . a : I ` : n v I ' h : n S E { b n d $ o a d h I d e [ a o n a : { ` . s t n e e a ] c d o n o $ t I t d n x r ; h y . n ` p { a d p e t . c ( _ b o $ t o r } : x r j h a v o . { i p g # / ' i s I n a d m o o t e x , e n n l y o p n i t y i s d o u _ t t s o _ w i . e e l i i . n r h i l x = , a v o b s e = f e ( > n a n a . g $ . n a g t s s b i { i g n { u i . e a o a o t n a o b U s n n / h o g n a r e n a , t e , s l U o p a , e } r . i t U / l t / i r c } a s o l a / r e n } n m g a s / v a e r , a a n t c n s i _ h o n f r / p $ e e 2 t t { s g / i a a t i c o t n . o o n i n j n n s o o s } t ) n . o ` e c n x { $ a ` t { n , . a v j n a s n s o o _ n . i ' i n , d d } e ` x , } ` , 生成される index.json:
{ } " " " " ] @ t t e c y o n { } o p t t n e a r " " " " " " " t " l i t l m a c m t e : E e e a o n a a a x n s x n t n n n r t " t " t g i o v i g " S r : " u v t a f e : e i : a a a s e t a e [ g t t I s " " r s " e i i d t : h c " こ " o o " I t h : の : n n : d " t I 画 " I " h p n 1 像 " : d " : t : d 2 は j " h t / e , 1 a " : t " p / x 6 " c t h : i " 世 , o " p t / i , 紀 m h : t / i の m t / p e f ゲ e t / : x . ッ n p e / a i テ t : x / m o ィ i / a e p / ン n / m x l a ゲ g e p a e p ン " x l m . i 地 , a e p c / 図 m . l o s で p c e m e す l o . / a 。 e m c c r " . / o a c , c c m n h o a / v / m n m a 2 / v a s / a a n / c n s i 1 o n f " n 1 e t t " s e a , t x t . t i j . o s j n o s / n o 1 " n " , " , , 2. Service Worker の実装# 検索リクエストをインターセプトし、クライアントサイドで処理する Service Worker を作成します。
c a } f } f } s } a } s s o s u u e ) s e e n y i } c c s r n c r n r } l c i } ; y c c c c c r } l l i 検 s 検 n f o o e e 検 c o e I c e ; F f o f n o o o o o e ) f f i 索 t 索 c r n n a t 索 t n t . . } I t t ' ' ' w } r } h } e . n e c n n n n n t h ; . . i イ イ ( e s s r u を i s u f m ) I i u @ @ @ i , e ) i ) t a s I ( v s s s s s u e a a f ン s ン f s t t t c r 実 o t r i a e m b a ) F o r c i t t ' t s ' ' m r } o ) t ' a m b a ) c d t I u e f t t t t t r a d d - デ e デ u e u h n 行 n n l p n a e f ; n n o d y h @ o o @ @ o e , n , s @ n a e f h d I r n u n d d d s ッ a ッ n a r r i I n t ( t t f t C n ' p i t t u i t t s ' c : : t n t f t E u F l t n q i i r r e E E e ク r ク c r n e n n i e o i e e r c 前 o e o f { t : e n y a r d y i o @ h y o c o e イ v r . . c u n n e e n r v v a ス c ス t c s d d n x r n r n y h 後 r r n o e ' : p l c ' p v u t a r r p t h r r ベ e l 検 p r t e d d s s e s e e r の h を i h s p e e d e m d ( t , : の e : t r x r : e : e : e a r y r . e e a : e : ン n 索 a e i r e e u p w : n n c キ I 読 o I e o x x e c a e e r コ : e m t e { ' s ' t c p s e s ' t : ト t = リ t s o y x x l o t t h ャ n み n n a n C x u l x n y q ン n a ' q ' : r : r : i e e : n u : i r r を L ク h p n U t n R { L L - ッ d 込 d r s = a ; t i . t u テ t t : u s e . o : ' t l o . r . ハ i n エ n o = r = s s e i i s シ e む l e c e c e z e r = e キ S e c ' s r e n : r r t ' n m . a ン s e ス a n h l e s ' s s w ュ x o x h a h S e n y > r ス S e ' s : s u e n o : { . y s s s a b f ド t w ト m d a u a = D p C t t . C a C I = w e e d t y ト e a h t A c l s t a ' e . . e : t e t ル e を e W n r = w a o o e e j a d a n a . a Q r = ( , を ' a r t U n : t u r : r c n t m a c f e n U イ . i d l a e t n n n n s c S c d a i s r u i > { 取 , r c t r n L s l y A . n t a a r [ h o r e R ン i t l . ` i x a s t e e h e h e w t e c e e 得 c h p l o a . t . n e t r r p c r , r r L タ n h e s $ t e e e r r e a e x a t h r s e h R : , t y l s a n n : y g ( h . e ( ( ー c ( S e { c = ( n ( ( r . C i r ( ( y n e / a e e . n o t C . e r : e , ' e セ l h e a u l u J t ' ' = c h a t e i i t A s / t r n m n t r o t t H n f v プ u a a r r o t f S - i a h a c s n n = r P p i i ' g a o a y n e = i t e e ト d n r c l a e o O T n c n I s h f p d d y I o i o , t p t t . t x > t r t n e d c h . d S r N y s t e n ( e e o e e q . n i n h ( a i m e t ' y c t s l h P o S e m . p t i w d i . t n x x u t 形 s f L r t o o n ( , . h . ( e R a r e a a s e a v e n g c s U , e e 式 e . i i n t t { a ' r ' S e r i a r t t ' l a M x d e h e r r x で ( i s = o ' i A n , e / e q a g r c S r : l t a ( e t ( . l q y t レ r o t > n , v s n q s a u m i c h e i ' e p i x ( i j , u . . ス e / ' I a T o ( u e r e s n h ( a n ' , ' ( n U i n s e t t ポ q a , ( d t e t e e a c s . } I i r g a , ) d r n d o i r o o ン u p { , i x a v s r h t g $ n n c i p ; e l d e n n y L L ス e i o t t e t c R ( e { d d h f p ( x ) e x ( d ) o o を s / n ' i n . h e r t u e e R y l e U ) x U ) e w w 生 t s , , o t u / q e ( r x x e ( i = v r U r ; x { e e 成 U e n ) r i u q ' l ( , s r c > e l { r l ) r r r a I l n e u q . i p e a n ) l ) ; C C l r d = ) d s e ' p n q o s t s t ) ; a a , c ] > ; e t s ) a d u n p i e ) { ; s s h , x ( t t e e s o o l e e r / { . e , h x r e n n f = ( ( e 1 j v n U y ( s / . > ) ) s / s e u a r ) r e j s . . u c o n r m l ; e D s k e t i l o n t l ' e ) q a o i v r n t n ' . ) ; } ; u t n p e i c s t ) r ` e a ' W n m l ) e e { ; s ) a t ( u x & q t , } i . ) d { t & u . t w ; e . e u { i a s j u s r n i ( s r t l g t n o l , , ( U o n . ) n r ' s u r ) t m , e r e ; i a a l s l l r ) u ( i c ) l c z h ; t l e P s i d a ) e Q r ; n u a t e m s r s . y . c ) h l ) a a s i ( m ' ( q ) ' ) ) ) ) ; { 3. Service Worker の登録# アプリケーション起動時に Service Worker を登録します。
e } x p i } t } } r o f r e r c r y c c r c c r g t ( o e o o e a o e i ! n t { n n t t n t s a ( s u s s u c s u t s ' o r t o r h o r e y s l n l n l n r n e e r e ( e - c r . f e . t e . f i v w a g l r r e a i f i a l i o u r r l i u c r s s g e o r s f n e n e t ( ; r o e - c W ( ; r ' ) r ; s t o ' a I ( e i r S t I { ' a o k e i I R r n e r o F e c r v n g h r ' i S i - e c = e s s g i e a t w i n a r r . s W w c a t t n o a h t s e a r i i r v k t S o I i e e n I g r n r I a a v f F t i v i a S o s i c i e r g e l a ) n a e r ) o t W d c t o o : h { r r ' S s . k , e u s e r p e r e v p r r i o v r r c r i e o e t c g r W e e i ) o d W s ; r ' o t k ) r e e ; k r r e e ( r d ) . ' : r ) e ; P g r i o s m t i e s r e ( < ' b / o i o i l i e f a - n s > e a { r c h - s w . j s ' ) ; 4. マニフェストへの検索サービス宣言# IIIF マニフェストに検索サービスを宣言します。
{ } " " " " ] @ i t s c d y e { } o " p r n : e v " " " " " t " i @ @ @ p l e " : c c i t r a x h e o d y o b t t " " n " p f e " t M : t : e i l : p a e " l " : n [ x " : e : " / i t h " h / f " t " : " t e e : t S S t x s p e " e p a t " : a h a : m " h / r t r / p , t / c t c / l t e h p h i e p x S : i . : a e / w i c / m r / i f o / p i t . m i l i i h i i e c i i m i . e f n / a f c 1 . a n . o " i t p i i m , o h i f o / i / e s a s p s a e p r t p a i m e . i r / a s j / c s n e s s h e i n o e / a f t n a i r e a " r n c s t , c d h t i h e / " o / x 1 n 1 . / / j s 3 c s e / o o a c n n r o t " c n e , h t x " e t , x . t j . s j o s n o " n , " , 5. Mirador での利用# Mirador の初期化前に Service Worker を登録するだけで、標準の検索機能が動作します。
i e } m x p p u } M o o s , i r r e r r t t E e [ a f g ] d { d f S i ) o e e e s ; r r f c r t M V e a t v e i i g u ( i r r e i l ( c I a w s t ) e I d e t I o r e f = W F r . r u > o S t I n r e 初 s I c { k a 期 x I t e r 化 F i r c S o h e n を S a 登 e r M 録 r c i v h r i S a c e d e r o W v r o i V r c i k e e e W w r o e ( r r ) k ( ; e { r m } a n f i r f o e m s t ' U @ r / l l i } b ) / r { e g i s t e r - i i i f - s e a r c h - s w ' ; 動作フロー# 1 2 3 4 5 6 7 8 9 1 . . . . . . . . . 0 . ユ ↓ S ↓ M ↓ ユ ↓ M G ↓ S ↓ 静 ↓ J ↓ I ↓ ー e i ー i E e 的 a I M ザ r r ザ r T r な v I i ー v a ー a v a F r が i d が d i i S a ペ c o 検 i c n c C d ー e r 索 r i e d r o o ジ ボ i e i n r を W が ッ が f W x p t 開 o マ ク 検 / o . t e が く r ニ ス 索 s r j n 検 k フ に リ i k s で t 索 e ェ 入 ク t e o 検 結 r ス 力 エ e r n 索 S 果 ト ス / を e を が を ト s が を 実 a 表 登 読 を e リ 取 行 r 示 録 み 送 a ク 得 c さ 込 信 r エ ( h れ み c ス キ る 、 h ト ャ A 検 / を ッ P 索 i イ シ I サ n ン ュ ー d タ ) 形 ビ e ー 式 ス x セ で を . プ レ 検 j ト ス 出 s ポ o ン n ス ? を q 生 = 成 地 図 メリットと制限# メリット# 項目 説明 静的サイト対応 GitHub Pages、Vercel、Netlify などで動作 サーバー不要 すべてクライアントサイドで完結 低コスト サーバー維持費が不要 高速 インデックスはブラウザにキャッシュされる Mirador 改修不要 標準の Mirador がそのまま使える
項目 説明 インデックスサイズ 大規模コレクションでは初回読み込みに時間がかかる HTTPS 必須 Service Worker は HTTPS 環境でのみ動作(localhost は例外) ブラウザ対応 IE11 非対応(モダンブラウザはすべて対応) 全文検索の限界 高度な全文検索エンジンほどの精度は出ない
大規模コレクションへの対応# インデックスサイズが大きくなる場合は、以下の対策が有効です:
インデックスの分割 : マニフェストごとにインデックスを分割遅延読み込み : 検索時に初めてインデックスを取得圧縮 : gzip 圧縮でファイルサイズを削減c o n マ s ニ t フ ェ i ス n ト d 別 e の x イ U ン r デ l ッ ク = ス U ` R / L i i i f / $ { s i t e I d } / 3 / $ { i t e m I d } / s e a r c h - i n d e x . j s o n ` ; まとめ# Service Worker を活用することで、静的サイトでも IIIF Content Search API を実現できます。この手法のポイントは:
ビルド時に検索インデックスを生成 Service Worker でリクエストをインターセプト クライアントサイドで検索を実行 IIIF 標準形式でレスポンスを返却 これにより、Mirador などの IIIF ビューアの改修なしに、静的サイトで検索機能を提供できます。デジタルアーカイブの構築において、サーバーレスでコストを抑えながら、リッチな検索体験を提供する選択肢として検討してみてください。
参考リンク#