Search Application クライアントを使用した検索体験の構築
この文書は、search applicationを使用して、Search Application clientで検索体験を構築するための手順ガイドです。このクライアントは、ブラウザで使用するために設計されたJavaScriptライブラリです。このライブラリをウェブアプリに統合して、検索アプリケーションへのクエリを簡素化します。
テストや実験のためのsandbox environmentが利用可能です。自分のウェブアプリを設定せずにクライアントを試したい場合は、こちらにジャンプしてください。
repositoryをクローンし、READMEの指示に従って始めてください。
目標
このガイドは、次の検索機能を持つウェブアプリを構築したいと仮定しています:
- カスタム関連性を持つ検索バーと結果
- フィールドの含め/除外や一致する用語のハイライトなど、結果の表示を制御
- ファセット、フィルター、ソート、ページネーションなどのUIコントロール
検索アプリケーションは、Elasticsearchに変更を永続化する「サーバーサイド」と考えることができます。あなたのウェブアプリは、検索アプリケーションにクエリを送信する「クライアントサイド」として機能します。実装を完了するために、検索アプリケーションとウェブアプリの両方を編集します。
前提条件
このガイドに従うには、次のものが必要です:
- Elastic deployment、検索アプリケーションを実行するための前提条件を満たすもの。
- Elastic deploymentがない場合は、Elastic Cloudで無料トライアルを開始してください。
- search application。
- web app、Search Application clientを使用して検索アプリケーションにクエリを送信します。
クライアントのインストールと設定
クライアントのインストール
npm、yarn、またはCDNを使用してクライアントをインストールします。
オプション 1: パッケージマネージャーを使用
npmを使用してクライアントをインストールするには、次のコマンドを実行します:
Bash
npm install @elastic/search-application-client
yarnを使用してクライアントをインストールするには、次のコマンドを実行します:
Bash
yarn add @elastic/search-application-client
オプション 2: HTML <script>
タグを使用したCDN
また、CDNを使用してクライアントをインストールすることもできます。次の<script>
タグをウェブアプリのHTMLに追加します:
Html
<script src="https://cdn.jsdelivr.net/npm/@elastic/search-application-client@latest"></script>
クライアントのインポートと初期化
インストールが完了したら、クライアントをウェブアプリにインポートできます。クライアントを初期化するには、次の情報が必要です:
- 検索アプリケーションの名前
- 検索アプリケーションのURLエンドポイント
- 検索アプリケーションのAPIキー
この情報は、Kibana UIのConnectページで見つけることができます。
オプション 1: JavaScriptモジュールを使用
次のインポート文を使用します:
Js
import SearchApplicationClient from '@elastic/search-application-client';
クライアントを初期化するために、デプロイメントの詳細でクライアントを設定します。APIキーはKibana UIのConnectページで生成できます。Search > Search Applications >
<MY_SEARCH_APPLICATION> > Connectに移動します。クライアントを初期化するために必要な情報が事前に入力されているのがわかります:
Js
import Client from '@elastic/search-application-client'
const request = Client(
'my-search-application', // search application name
'url-from-connect-page', // url-host
'api-key-from-connect-page', // api-key
{
// optional configuration
}
)
設定が完了すると、client APIを使用して検索アプリケーションに検索リクエストを送信できるようになります。次のように:
Js
const results = await request()
.query('star wars')
.search()
オプション 2: CDNを使用
CDNを使用している場合は、次の文を使用してクライアントをインポートできます:
Html
<script>
const Client = window['SearchApplicationClient'];
</script>
デプロイメントの詳細でクライアントを設定して、検索リクエストを送信できるようにします。APIキーはKibana UIのConnectページで生成できます。Search > Search Applications >
<MY_SEARCH_APPLICATION> > Connectに移動します。クライアントを初期化するために必要な情報が事前に入力されているのがわかります:
Html
<script>
const request = Client(
'my-example-app', // search application name
'url-from-connect-page', // url-host
'api-key-from-connect-page', // api-key
{
// optional configuration
}
)
</script>
設定が完了すると、client APIを使用して検索アプリケーションに検索リクエストを送信できるようになります。次のように:
Html
<script>
const results = await request()
.query('star wars')
.search()
</script>
検索テンプレートの操作
Search Application clientは、作成した任意のsearch templateと連携するように設計されています。Search Application APIsを使用して、検索テンプレートを作成および管理します。
テンプレートを管理するためにSearch Application APIsを使用する際には、Kibana Console構文を使用したAPIの例を提供します。
以下はテンプレートの例です:
Python
resp = client.search_application.put(
name="my-example-app",
search_application={
"indices": [
"my-example-app"
],
"template": {
"script": {
"lang": "mustache",
"source": "\n {\n \"query\": {\n \"bool\": {\n \"must\": [\n {{#query}}\n {\n \"query_string\": {\n \"query\": \"{{query}}\",\n \"search_fields\": {{#toJson}}search_fields{{/toJson}}\n }\n }\n {{/query}}\n ]\n }\n }\n }\n ",
"params": {
"query": "",
"search_fields": ""
}
}
}
},
)
print(resp)
Js
const response = await client.searchApplication.put({
name: "my-example-app",
search_application: {
indices: ["my-example-app"],
template: {
script: {
lang: "mustache",
source:
'\n {\n "query": {\n "bool": {\n "must": [\n {{#query}}\n {\n "query_string": {\n "query": "{{query}}",\n "search_fields": {{#toJson}}search_fields{{/toJson}}\n }\n }\n {{/query}}\n ]\n }\n }\n }\n ',
params: {
query: "",
search_fields: "",
},
},
},
},
});
console.log(response);
Console
PUT _application/search_application/my-example-app
{
"indices": ["my-example-app"],
"template": {
"script": {
"lang": "mustache",
"source": """
{
"query": {
"bool": {
"must": [
{{#query}}
{
"query_string": {
"query": "{{query}}",
"search_fields": {{#toJson}}search_fields{{/toJson}}
}
}
{{/query}}
]
}
}
}
""",
"params": {
"query": "",
"search_fields": ""
}
}
}
}
これにより、テンプレートに必要な任意のテンプレートパラメータを追加し、クライアントリクエストで値を提供できます。addParameter
を使用して、テンプレートパラメータに実際の値を注入します。
たとえば、search_fields
の値を次のように渡します:
Js
const results = await request()
.query('star wars') // requires the template to use query parameter
.addParameter('search_fields', ['title', 'description'])
.search()
例のテンプレート
クライアントリポジトリに提供されているboilerplate templateから始めることをお勧めします。このスクリプトを表示して、どのように使用されているかを確認してください。dictionary
パラメータは、リクエストオブジェクトの構造と検証ルールを説明するJSONスキーマ定義を渡すために使用されます。このスキーマは重要であり、Elasticsearchクエリの特定の機能の使用を制限します。スキーマを表示。
このガイドの各検索機能は、このテンプレートに含まれる機能を必要とします。これらの機能は、テンプレートに特定のパラメータが存在することを要求します:
- クエリ:
query
- フィルター:
_es_filters
- ファセット:
_es_filters
および_es_aggs
- ソート:
_es_sort_fields
- ページネーション:
from
およびsize
検索機能
検索体験に必要な基本的な要素をすべて探求します。検索アプリケーションを使用してそれらを実装し、クライアントを使用してクエリを送信する方法を学びます。
利用可能なメソッドとそのパラメータに関する情報は、client repoを参照してください。
関連性のカスタマイズ
私たちのシンプルなテンプレートは、すべてのフィールドにわたってquery_string
検索を使用していますが、これはあなたのユースケースに合わないかもしれません。テンプレートを更新して、より良い関連性のリコールを提供できます。
以下の例では、multi-match
クエリをテンプレートに対して使用し、best_fields
およびphrase_prefix
クエリが異なる検索フィールドをターゲットにしています。
Python
resp = client.search_application.put(
name="my-example-app",
search_application={
"indices": [
"example-index"
],
"template": {
"script": {
"lang": "mustache",
"source": "\n {\n \"query\": {\n \"bool\": {\n \"must\": [\n {{#query}}\n {\n \"multi_match\" : {\n \"query\": \"{{query}}\",\n \"fields\": [ \"title^4\", \"plot\", \"actors\", \"directors\" ]\n }\n },\n {\n \"multi_match\" : {\n \"query\": \"{{query}}\",\n \"type\": \"phrase_prefix\",\n \"fields\": [ \"title^4\", \"plot\"]\n }\n },\n {{/query}}\n ],\n \"filter\": {{#toJson}}_es_filters{{/toJson}}\n }\n },\n \"aggs\": {{#toJson}}_es_aggs{{/toJson}},\n \"from\": {{from}},\n \"size\": {{size}},\n \"sort\": {{#toJson}}_es_sort_fields{{/toJson}}\n }\n ",
"params": {
"query": "",
"_es_filters": {},
"_es_aggs": {},
"_es_sort_fields": {},
"size": 10,
"from": 0
},
"dictionary": {}
}
}
},
)
print(resp)
Js
const response = await client.searchApplication.put({
name: "my-example-app",
search_application: {
indices: ["example-index"],
template: {
script: {
lang: "mustache",
source:
'\n {\n "query": {\n "bool": {\n "must": [\n {{#query}}\n {\n "multi_match" : {\n "query": "{{query}}",\n "fields": [ "title^4", "plot", "actors", "directors" ]\n }\n },\n {\n "multi_match" : {\n "query": "{{query}}",\n "type": "phrase_prefix",\n "fields": [ "title^4", "plot"]\n }\n },\n {{/query}}\n ],\n "filter": {{#toJson}}_es_filters{{/toJson}}\n }\n },\n "aggs": {{#toJson}}_es_aggs{{/toJson}},\n "from": {{from}},\n "size": {{size}},\n "sort": {{#toJson}}_es_sort_fields{{/toJson}}\n }\n ',
params: {
query: "",
_es_filters: {},
_es_aggs: {},
_es_sort_fields: {},
size: 10,
from: 0,
},
dictionary: {},
},
},
},
});
console.log(response);
Console
PUT _application/search_application/my-example-app
{
"indices": ["example-index"],
"template": {
"script": {
"lang": "mustache",
"source": """
{
"query": {
"bool": {
"must": [
{{#query}}
{
"multi_match" : {
"query": "{{query}}",
"fields": [ "title^4", "plot", "actors", "directors" ]
}
},
{
"multi_match" : {
"query": "{{query}}",
"type": "phrase_prefix",
"fields": [ "title^4", "plot"]
}
},
{{/query}}
],
"filter": {{#toJson}}_es_filters{{/toJson}}
}
},
"aggs": {{#toJson}}_es_aggs{{/toJson}},
"from": {{from}},
"size": {{size}},
"sort": {{#toJson}}_es_sort_fields{{/toJson}}
}
""",
"params": {
"query": "",
"_es_filters": {},
"_es_aggs": {},
"_es_sort_fields": {},
"size": 10,
"from": 0
},
"dictionary": {
// add dictionary restricting
// _es_filters, _es_sort_fields & _es_aggs params
// Use example provided in repo: https://github.com/elastic/search-application-client/blob/main/bin/request_schema.json
}
}
}
}
テキスト検索、kNN検索、ELSER検索、RRFを使用したハイブリッド検索など、さまざまなタイプのクエリの例を参照してください。
ユースケース: 検索フィールドを動的に調整したい
クエリリクエスト時にsearch_fields
を調整する必要がある場合は、テンプレートに新しいパラメータ(たとえば: search_fields
)を追加し、addParameter
メソッドを使用してフィールドをテンプレートに提供できます。
ユースケース: ユーザーに近い結果を強化したい
ユーザーのジオコーディネートを送信するために追加のテンプレートパラメータを追加できます。次に、特定のgeo_distance
に一致するドキュメントを強化するためにfunction_score
を使用します。
結果フィールド
デフォルトでは、すべてのフィールドが_source
フィールドに返されます。返されるフィールドを制限するには、テンプレートでフィールドを指定します。
Python
resp = client.search_application.put(
name="my-example-app",
search_application={
"indices": [
"example-index"
],
"template": {
"script": {
"lang": "mustache",
"source": "\n {\n \"query\": {\n \"bool\": {\n \"must\": [\n {{#query}}\n \n {{/query}}\n ],\n \"filter\": {{#toJson}}_es_filters{{/toJson}}\n }\n },\n \"_source\": {\n \"includes\": [\"title\", \"plot\"]\n },\n \"aggs\": {{#toJson}}_es_aggs{{/toJson}},\n \"from\": {{from}},\n \"size\": {{size}},\n \"sort\": {{#toJson}}_es_sort_fields{{/toJson}}\n }\n ",
"params": {
"query": "",
"_es_filters": {},
"_es_aggs": {},
"_es_sort_fields": {},
"size": 10,
"from": 0
},
"dictionary": {}
}
}
},
)
print(resp)
Js
const response = await client.searchApplication.put({
name: "my-example-app",
search_application: {
indices: ["example-index"],
template: {
script: {
lang: "mustache",
source:
'\n {\n "query": {\n "bool": {\n "must": [\n {{#query}}\n \n {{/query}}\n ],\n "filter": {{#toJson}}_es_filters{{/toJson}}\n }\n },\n "_source": {\n "includes": ["title", "plot"]\n },\n "aggs": {{#toJson}}_es_aggs{{/toJson}},\n "from": {{from}},\n "size": {{size}},\n "sort": {{#toJson}}_es_sort_fields{{/toJson}}\n }\n ',
params: {
query: "",
_es_filters: {},
_es_aggs: {},
_es_sort_fields: {},
size: 10,
from: 0,
},
dictionary: {},
},
},
},
});
console.log(response);
Console
PUT _application/search_application/my-example-app
{
"indices": ["example-index"],
"template": {
"script": {
"lang": "mustache",
"source": """
{
"query": {
"bool": {
"must": [
{{#query}}
// ...
{{/query}}
],
"filter": {{#toJson}}_es_filters{{/toJson}}
}
},
"_source": {
"includes": ["title", "plot"]
},
"aggs": {{#toJson}}_es_aggs{{/toJson}},
"from": {{from}},
"size": {{size}},
"sort": {{#toJson}}_es_sort_fields{{/toJson}}
}
""",
"params": {
"query": "",
"_es_filters": {},
"_es_aggs": {},
"_es_sort_fields": {},
"size": 10,
"from": 0
},
"dictionary": {
// add dictionary restricting _es_filters and _es_aggs params
// Use the dictionary example provided in repo: https://github.com/elastic/search-application-client/blob/main/bin/request_schema.json
}
}
}
}
ユースケース: 結果フィールドを動的に調整したい
クエリリクエスト時に返されるフィールドを調整する必要がある場合は、テンプレートに新しいパラメータ(たとえば: result_fields
)を追加し、addParameter
メソッドを使用してフィールドをテンプレートに提供できます。
ハイライトとスニペット
ハイライトサポートは、テンプレートに簡単に追加できます。highlighting APIを使用して、一致するフィールドを指定できます。
以下の例では、title
およびplot
をハイライトフィールドとして指定します。title
は通常、plot
に比べて短い値の長さを持ち、plot
は可変で長くなる傾向があります。
ハイライトがある場合、タイトルをfragment_size
の0
として指定し、すべてのテキストを返します。プロットをfragment_size
の200
として指定し、各ハイライトされたフラグメントは最大200文字の長さになります。
Python
resp = client.search_application.put(
name="my-example-app",
search_application={
"indices": [
"example-index"
],
"template": {
"script": {
"lang": "mustache",
"source": "\n {\n \"query\": {\n \"bool\": {\n \"must\": [\n {{#query}}\n \n {{/query}}\n ],\n \"filter\": {{#toJson}}_es_filters{{/toJson}}\n }\n },\n \"_source\": {\n \"includes\": [\"title\", \"plot\"]\n },\n \"highlight\": {\n \"fields\": {\n \"title\": { \"fragment_size\": 0 },\n \"plot\": { \"fragment_size\": 200 }\n }\n },\n \"aggs\": {{#toJson}}_es_aggs{{/toJson}},\n \"from\": {{from}},\n \"size\": {{size}},\n \"sort\": {{#toJson}}_es_sort_fields{{/toJson}}\n }\n ",
"params": {
"query": "",
"_es_filters": {},
"_es_aggs": {},
"_es_sort_fields": {},
"size": 10,
"from": 0
},
"dictionary": {}
}
}
},
)
print(resp)
Js
const response = await client.searchApplication.put({
name: "my-example-app",
search_application: {
indices: ["example-index"],
template: {
script: {
lang: "mustache",
source:
'\n {\n "query": {\n "bool": {\n "must": [\n {{#query}}\n \n {{/query}}\n ],\n "filter": {{#toJson}}_es_filters{{/toJson}}\n }\n },\n "_source": {\n "includes": ["title", "plot"]\n },\n "highlight": {\n "fields": {\n "title": { "fragment_size": 0 },\n "plot": { "fragment_size": 200 }\n }\n },\n "aggs": {{#toJson}}_es_aggs{{/toJson}},\n "from": {{from}},\n "size": {{size}},\n "sort": {{#toJson}}_es_sort_fields{{/toJson}}\n }\n ',
params: {
query: "",
_es_filters: {},
_es_aggs: {},
_es_sort_fields: {},
size: 10,
from: 0,
},
dictionary: {},
},
},
},
});
console.log(response);
Console
PUT _application/search_application/my-example-app
{
"indices": ["example-index"],
"template": {
"script": {
"lang": "mustache",
"source": """
{
"query": {
"bool": {
"must": [
{{#query}}
// ...
{{/query}}
],
"filter": {{#toJson}}_es_filters{{/toJson}}
}
},
"_source": {
"includes": ["title", "plot"]
},
"highlight": {
"fields": {
"title": { "fragment_size": 0 },
"plot": { "fragment_size": 200 }
}
},
"aggs": {{#toJson}}_es_aggs{{/toJson}},
"from": {{from}},
"size": {{size}},
"sort": {{#toJson}}_es_sort_fields{{/toJson}}
}
""",
"params": {
"query": "",
"_es_filters": {},
"_es_aggs": {},
"_es_sort_fields": {},
"size": 10,
"from": 0
},
"dictionary": {
// add dictionary restricting _es_filters and _es_aggs params
// Use the dictionary example provided in repo: https://github.com/elastic/search-application-client/blob/main/bin/request_schema.json
}
}
}
}
一致が見つかった場合、これはハイライトフィールドを持つ結果を返します。たとえば:
Js
{
"hits": [
{
"_index": "movies",
"_type": "_doc",
"_id": "1",
"_score": 0.2876821,
"_source": {
"title": "The Great Gatsby",
"plot": "The Great Gatsby is a novel by F. Scott Fitzgerald that follows the story of Jay Gatsby, a wealthy and mysterious man, as he tries to win back the love of his life, Daisy Buchanan."
},
"highlight": {
"title": ["The Great <em>Gatsby</em>"],
"plot": [
"The Great <em>Gatsby</em> is a novel by F. Scott Fitzgerald that follows the story of <em>Jay</em> <em>Gatsby</em>, a wealthy and mysterious man, as he tries to win back the love of his life, Daisy Buchanan."
]
}
}
]
}
ハイライトヘルパー
フロントエンドでフィールドを表示する際に、フィールドにハイライトがあるかどうかを最初に判断する必要があります。これを簡素化するために、ヘルパーを提供します。
Js
import Client, { Highlight } from '@elastic/search-application-client'
// example React component
const ResultsList = ({ hits } ) => {
return hits.map((hit) => (
<div className="result">
<div className="title">{Highlight(hit, "title")}</div>
<div className="description">{Highlight(hit, "plot")}</div>
</div>
))
}
ページネーション
ページネーションを使用するには、ページ番号とページサイズを設定します。デフォルトでは、ページサイズは10です。size
およびfrom
パラメータを使用して、レスポンスで返されるページとヒット数を制御できます。
クライアントを使用して、setSize
およびsetFrom
メソッドでこれを行うことができます。
Js
// page 1
const results = await request()
.setSize(20)
.setFrom(0)
.search()
// page 2
const results = await request()
.setSize(20)
.setFrom(20)
.search()
ソート
ソートを使用するには、フィールド名とソート順序を指定するか、関連性でソートするためにpass _score
を指定します。検索テンプレートには_es_sort_fields_fields
パラメータが必要です。これがどこで使用されているかを確認するには、example templateを参照してください。
デフォルトでは、結果はスコアの順にソートされます。スコア以外のフィールドでソートする必要がある場合は、setSort
メソッドを使用してオブジェクトの配列を指定します。
Js
const results = await request()
.setSort([{ year: 'asc' }, '_score'])
.search()
フィルタリング
Search application clientは、フィルターとファセットもサポートしています。これらを使用するには、2つのパラメータを追加する必要があります:
_es_filters
_es_aggs
これらがどこで使用されているかを確認するには、example templateを参照してください。
基本フィルタリング
フィルターを使用するように設定されたテンプレートを使用して、setFilter
メソッドを使用してクエリにフィルターを追加します。
ボイラープレートテンプレートスキーマは、term、range、match、nested、geo_bounding_box、およびgeo_distanceフィルターのみをサポートします。特定の句を使用する必要がある場合は、テンプレートスキーマを更新できます。
以下はsetFilter
を使用した例です。
Js
// return only "star wars" movies that are rated PG
const results = await request()
.query('star wars')
.setFilter({
term: {
'rated.enum': 'PG',
},
})
.search()
ファセット
クライアントは、結果にファセットを設定する機能をサポートしています。クライアント初期化呼び出しでファセットを指定します。たとえば、俳優、監督、IMDB評価のファセットを追加したいとします。
Js
const request = Client(
'my-example-app', // search application name
'https://d1bd36862ce54c7b903e2aacd4cd7f0a.us-east4.gcp.elastic-cloud.com:443', // api-host
'api-key-from-connect-page', // api-key
{
facets: {
actors: {
type: 'terms',
field: 'actors.keyword',
disjunctive: true,
},
directors: {
type: 'terms',
field: 'director.keyword',
size: 20,
disjunctive: true,
},
imdbrating: {
type: 'stats',
field: 'imdbrating',
},
},
}
)
Elasticsearchでは、keyword
タイプは、正確で変更されていない形式で検索可能である必要があるフィールドに使用されます。これは、これらのクエリが大文字と小文字を区別することを意味します。このタイプは、ファセットが正確な値や用語に基づいてデータを集約およびフィルタリングする必要があるため、ファセットに使用されます。
以下の例では、映画のみを返したいとします:
- ハリソン・フォードを俳優としてフィーチャー
- ジョージ・ルーカスまたはリドリー・スコットが監督
- IMBD評価が7.5を超える
#### Js
``````js
const results = await request()
.addFacetFilter('actors', 'Harrison Ford')
.addFacetFilter('directors', 'George Lucas')
.addFacetFilter('directors', 'Ridley Scott')
.addFacetFilter('imdbrating', {
gte: 7.5,
})
.search()
`
結果のファセットにアクセスできます:
検索アプリケーションクライアントを使用した検索体験の構築
この文書は、search applicationを使用して、Search Application clientで検索体験を構築するための手順ガイドです。このクライアントは、ブラウザで使用するために設計されたJavaScriptライブラリです。このライブラリをウェブアプリに統合して、検索アプリケーションへのクエリを簡素化します。
サンドボックス環境は、search-application-client
ライブラリをテストおよび実験するために利用可能です。自分のウェブアプリを設定せずにクライアントを試したい場合は、そこにジャンプしてください。
repositoryをクローンし、READMEの指示に従って始めてください。