これはPGroonga 2.X and 3.X用のドキュメントです。古いPGroongaを使っているならPGroonga 1.xのドキュメントを見てください。
pgroonga_highlight_html
関数1.0.7で追加。
pgroonga_highlight_html
関数は指定したテキスト中にある指定したキーワードを<span class="keyword">
と</span>
で囲みます。指定したテキスト中にある&
などのHTMLの特別な文字はエスケープされます。
使い方は2つあります。
text pgroonga_highlight_html(target, ARRAY[keyword1, keyword2, ...])
text pgroonga_highlight_html(target, ARRAY[keyword1, keyword2, ...], index_name)
text[] pgroonga_highlight_html(ARRAY[target1, target2, ...],
ARRAY[keyword1, keyword2, ...])
text[] pgroonga_highlight_html(ARRAY[target1, target2, ...],
ARRAY[keyword1, keyword2, ...], index_name)
1つ目の使い方は他の使い方よりもシンプルです。多くの場合は1つ目の使い方で十分です。
2つ目の使い方はノーマライザーを変更しているときに便利です。
2つ目の使い方は2.0.7から使えます。
3つ目と4つ目の使い方は1つ目と2つ目の使い方のtext[]
バージョンです。
3つ目と4つ目の使い方は2.4.3から使えます。
以下は1つ目の使い方の説明です。
text pgroonga_highlight_html(target, ARRAY[keyword1, keyword2, ...])
target
はハイライト対象のテキストです。型はtext
です。
キーワードは<span class="keyword">
と</span>
で囲まれています。target
中の<
、>
、&
、"
はHTMLエスケープされます。
pgroonga_highlight_html
はtarget
中のキーワードをマークアップします。型はtext
です。
キーワードは<span class="keyword">
と</span>
で囲まれます。target
中の<
、>
、&
、"
はHTMLエスケープされます。
以下は2つ目の使い方の説明です。
text pgroonga_highlight_html(target, ARRAY[keyword1, keyword2, ...], index_name)
target
はハイライト対象のテキストです。型はtext
です。
キーワードは<span class="keyword">
と</span>
で囲まれています。target
中の<
、>
、&
、"
はHTMLエスケープされます。
index_name
は対応するPGroongaのインデックス名です。text
型です。
index_name
にはNULL
を指定できます。
NormalizerNFKC100
のようにNormalizerAuto
以外のノーマライザーを使っている場合は、index_name
を使うとよいです。この関数はデフォルトでNormalizerAuto
ノーマライザーを使います。これにより意図しない結果になることがあります。
index_name
を指定した場合は、指定したPGroongaのインデックスには"report_source_location"
オプションを指定したTokenNgram
トークナイザーを指定しないといけません。
例です。
CREATE TABLE memos (
content text
);
CREATE INDEX pgroonga_content_index
ON memos
USING pgroonga (content)
WITH (tokenizer='TokenNgram("report_source_location", true)',
normalizer='NormalizerNFKC100');
これでindex_name
にpgroonga_content_index
を指定できます。
SELECT pgroonga_highlight_html('one two three four five',
ARRAY['two three', 'five'],
'pgroonga_content_index');
-- pgroonga_highlight_html
-- -----------------------------------------------------------------------------------
-- one<span class="keyword"> two three</span> four<span class="keyword"> five</span>
-- (1 row)
pgroonga_highlight_html
はtarget
中のキーワードをマークアップします。型はtext
です。
キーワードは<span class="keyword">
と</span>
で囲まれます。target
中の<
、>
、&
、"
はHTMLエスケープされます。
2.0.7から使えます。
以下は3つ目の使い方の説明です。
text[] pgroonga_highlight_html(ARRAY[target1, target2, ...],
ARRAY[keyword1, keyword2, ...])
target1
、target2
、...
はハイライト対象のテキストです。型はtext
の配列です。
キーワードは<span class="keyword">
と</span>
で囲まれています。target
中の<
、>
、&
、"
はHTMLエスケープされます。
pgroonga_highlight_html
は各target
中のキーワードをマークアップします。pgroonga_highlight_html
はtext
型の配列を返します。もし、あるtarget
がNULL
の場合は返ってくる配列の中の対応する要素もNULL
になります。
キーワードは<span class="keyword">
と</span>
で囲まれます。target
中の<
、>
、&
、"
はHTMLエスケープされます。
SELECT pgroonga_highlight_html(ARRAY['one two three', NULL, 'five', 'six three'],
ARRAY['two three', 'six']);
-- pgroonga_highlight_html
-- -------------------------------------------------------------------------------------------------------
-- {"one<span class=\"keyword\"> two three</span>",NULL,five,"<span class=\"keyword\">six</span> three"}
-- (1 row)
2.4.2から使えます。
以下は4つ目の使い方の説明です。
text[] pgroonga_highlight_html(ARRAY[target1, target2, ...],
ARRAY[keyword1, keyword2, ...],
index_name)
target1
、target2
、...
はハイライト対象のテキストです。型はtext
の配列です。
キーワードは<span class="keyword">
と</span>
で囲まれています。target
中の<
、>
、&
、"
はHTMLエスケープされます。
index_name
は対応するPGroongaのインデックス名です。text
型です。
index_name
にはNULL
を指定できます。
NormalizerNFKC100
のようにNormalizerAuto
以外のノーマライザーを使っている場合は、index_name
を使うとよいです。この関数はデフォルトでNormalizerAuto
ノーマライザーを使います。これにより意図しない結果になることがあります。
index_name
を指定した場合は、指定したPGroongaのインデックスには"report_source_location"
オプションを指定したTokenNgram
トークナイザーを指定しないといけません。
pgroonga_highlight_html
は各target
中のキーワードをマークアップします。pgroonga_highlight_html
はtext
型の配列を返します。もし、あるtarget
がNULL
の場合は返ってくる配列の中の対応する要素もNULL
になります。
キーワードは<span class="keyword">
と</span>
で囲まれます。target
中の<
、>
、&
、"
はHTMLエスケープされます。
2つ目の使い方の例と3つ目の使い方の例も見てください。
2.4.2から使えます。
少なくとも1つキーワードを指定しなければいけません。
SELECT pgroonga_highlight_html('PGroonga is a PostgreSQL extension.',
ARRAY['PostgreSQL']) AS highlight_html;
-- highlight_html
-- ------------------------------------------------------------------
-- PGroonga is a <span class="keyword">PostgreSQL</span> extension.
-- (1 row)
複数のキーワードを指定できます。
SELECT pgroonga_highlight_html('PGroonga is a PostgreSQL extension.',
ARRAY['Groonga', 'PostgreSQL']) AS highlight_html;
-- highlight_html
-- -----------------------------------------------------------------------------------------------
-- P<span class="keyword">Groonga</span> is a <span class="keyword">PostgreSQL</span> extension.
-- (1 row)
pgroonga_query_extract_keywords
関数を使うとクエリーからキーワードを抽出できます。
SELECT pgroonga_highlight_html('PGroonga is a PostgreSQL extension.',
pgroonga_query_extract_keywords('Groonga PostgreSQL -extension')) AS highlight_html;
-- highlight_html
-- -----------------------------------------------------------------------------------------------
-- P<span class="keyword">Groonga</span> is a <span class="keyword">PostgreSQL</span> extension.
-- (1 row)
HTMLの特別な文字は自動でエスケープされます。
SELECT pgroonga_highlight_html('<p>PGroonga is Groonga & PostgreSQL.</p>',
ARRAY['PostgreSQL']) AS highlight_html;
-- highlight_html
-- ---------------------------------------------------------------------------------------
-- <p>PGroonga is Groonga & <span class="keyword">PostgreSQL</span>.</p>
-- (1 row)
文字は正規化されます。
SELECT pgroonga_highlight_html('PGroonga + pglogical = replicatable!',
ARRAY['Pg']) AS highlight_html;
-- highlight_html
-- ------------------------------------------------------------------------------------------------
-- <span class="keyword">PG</span>roonga + <span class="keyword">pg</span>logical = replicatable!
-- (1 row)
マルチバイト文字にも対応しています。
SELECT pgroonga_highlight_html('10㌖先にある100キログラムの米',
ARRAY['キロ']) AS highlight_html;
-- highlight_html
-- ---------------------------------------------------------------------------------------
-- 10<span class="keyword">㌖</span>先にある100<span class="keyword">キロ</span>グラムの米
-- (1 row)
PGroongaのインデックス名を指定するとトークナイザーとノーマライザーをカスタマイズできます。
CREATE TABLE memos (
content text
);
CREATE INDEX pgroonga_content_index
ON memos
USING pgroonga (content)
WITH (tokenizer='TokenNgram("report_source_location", true)',
normalizer='NormalizerNFKC100');
SELECT pgroonga_highlight_html('one two three four five',
ARRAY['two three', 'five'],
'pgroonga_content_index');
-- pgroonga_highlight_html
-- -----------------------------------------------------------------------------------
-- one<span class="keyword"> two three</span> four<span class="keyword"> five</span>
-- (1 row)
以下はpgroonga_highlight_html
を使ってキーワード検索機能を実装する例です。
ブログを開発することを想像してください。単純にするために、このブログの記事のモデルはid
、title
、body
フィールドしかありません。
CREATE TABLE posts (
id SERIAL NOT NULL,
title varchar(255),
body text
);
-- Create PGroonga Index
CREATE INDEX pgroonga_posts_index
ON posts
USING pgroonga (title, body);
-- Insert some sample data
INSERT INTO posts VALUES (1, 'Quote of the day one', 'Design is not just what it looks like and feels like. Design is how it works.');
INSERT INTO posts VALUES (2, 'Quote of the day two', 'If everyone is busy making everything, how can any one perfect anything?');
INSERT INTO posts VALUES (3, 'Quote of the day three', 'There are a thousand no''s, for every yes.');
ブログ記事を検索し、検索キーワードがハイライトされた結果を返すために、次のようにpgroonga_highlight_html
関数を使えます。
SELECT
pgroonga_highlight_html(title, pgroonga_query_extract_keywords('thousand')) AS highlighted_title,
pgroonga_highlight_html(body, pgroonga_query_extract_keywords('thousand')) AS highlighted_body
from posts where title &@~ 'thousand' or body &@~ 'thousand';
-- highlighted_title | highlighted_body
-- ------------------------+------------------------------------------------------------------------
-- Quote of the day three | There are a <span class="keyword">thousand</span> no's, for every yes.
-- (1 row)
もし、検索対象のページがたくさん会ってページネーションを使って結果を返す必要がある場合、そのクエリーでpgroonga_highlight_html()
を使わないほうがいいかもしれません。なぜならpgroonga_highlight_html()
はシーケンシャルにしか動かないからです。pgroonga_highlight_html()
で処理しなければいけないレコード数が増えるほど遅くなります。
この問題を避けるために、次の例ではpgroonga_highlight_html()
対象のレコードを減らしています。サブクエリーで返却対象のレコード数を絞り込んでからpgroonga_highlight_html()
を使っています。
-- Good Performance
SELECT
pgroonga_highlight_html(title, pgroonga_query_extract_keywords('Search Words')) AS highlighted_title,
pgroonga_highlight_html(body, pgroonga_query_extract_keywords('Search Words')) AS highlighted_body
from posts where id IN
(SELECT id FROM posts where title &@~ 'Search Words' or body &@~ 'Search Words' LIMIT 10 OFFSET 100);
-- Do not do this. You may experience some performance issue.
SELECT
pgroonga_highlight_html(title, pgroonga_query_extract_keywords('Search Words')) AS highlighted_title,
pgroonga_highlight_html(body, pgroonga_query_extract_keywords('Search Words')) AS highlighted_body
from posts where title &@~ 'Search Words' or body &@~ 'Search Words' LIMIT 10 OFFSET 100;
NormalizerTable
を使うときのキーワード検索とハイライトCREATE INDEX USING pgroonga
のドキュメント(pgroonga_highlight_html
と一緒にNormalizerTable
を使う方法セクション)のようにNormalizerTable
を指定した場合、指定したPGroongaのインデックスはTokenNgram
に"report_source_location", true"
オプションを指定するだけではなくNormalizerNFKC*
とNormalizerTable
の両方にそれぞれ"report_source_offset", true"
オプションを指定してしなければいけません。
以下は指定する例です。ここではたくさんの表記がある斉藤
を使います。
CREATE TABLE memos (
content text
);
CREATE TABLE synonyms (
"target" text not null,
"normalized" text not null
);
INSERT INTO synonyms VALUES ('齊', '斉');
INSERT INTO synonyms VALUES ('斎', '斉');
INSERT INTO synonyms VALUES ('齋', '斉');
INSERT INTO memos (content) VALUES ('斎藤さんの恋愛');
INSERT INTO memos (content) VALUES ('斉藤さんの失恋');
INSERT INTO memos (content) VALUES ('齋藤さんの片想い');
CREATE INDEX pgroonga_synonyms_index ON synonyms
USING pgroonga (target pgroonga_text_term_search_ops_v2)
INCLUDE (normalized);
CREATE INDEX pgroonga_memos_index
ON memos
USING pgroonga (content)
WITH (
tokenizer='TokenNgram(
"unify_alphabet", false,
"unify_symbol", false,
"unify_digit", false,
"report_source_location", true
)',
normalizers='
NormalizerNFKC150("report_source_offset", true),
NormalizerTable(
"normalized", "${table:pgroonga_synonyms_index}.normalized",
"target", "target",
"report_source_offset", true
)'
);
select pgroonga_highlight_html(content, '{斉藤}', 'pgroonga_memos_index')
from memos where content &@~ '斉藤';
-- pgroonga_highlight_html
-- -----------------------------------------------
-- <span class="keyword"></span>斎藤さんの恋愛
-- <span class="keyword"></span>斉藤さんの失恋
-- <span class="keyword"></span>齋藤さんの片想い
-- (3 rows)