テンプレート処理中にエラーが発生しました。
Java method "com.liferay.portal.json.JSONFactoryImpl.createJSONObject(String)" threw an exception when invoked on com.liferay.portal.json.JSONFactoryImpl object "com.liferay.portal.json.JSONFactoryImpl@51577ebb"; see cause exception in the Java stack trace.

----
FTL stack trace ("~" means nesting-related):
	- Failed at: navigationJSONObject = jsonFactoryUti...  [in template "17855804202317#32484267#LEARN-ARTICLE-NAV" at line 4, column 9]
----
1<#assign 
2	groupFriendlyURL = themeDisplay.getScopeGroup().getFriendlyURL() 
3	groupPathFriendlyURLPublic = themeDisplay.getPathFriendlyURLPublic() + groupFriendlyURL 
4	navigationJSONObject = jsonFactoryUtil.createJSONObject(navigation.getData()) 
5	navigationMenuItems = 
6
7			"Analytics Cloud": { 
8				"image": "/documents/d${groupFriendlyURL}/analytics_c-svg", 
9				"title": "Analytics Cloud", 
10				"url": "analytics-cloud" 
11			}, 
12			"Commerce": { 
13				"image": "/documents/d${groupFriendlyURL}/commerce_product-svg", 
14				"title": "Commerce", 
15				"url": "commerce" 
16			}, 
17			"DXP": { 
18				"image": "/documents/d${groupFriendlyURL}/dxp_p-svg", 
19				"title": "DXP / Portal", 
20				"url": "dxp" 
21			}, 
22			"Liferay Cloud": { 
23				"image": "/documents/d${groupFriendlyURL}/dxp_c-svg", 
24				"title": "Liferay Cloud", 
25				"url": "liferay-cloud" 
26			}, 
27			"Reference": { 
28				"image": "/documents/d${groupFriendlyURL}/reference-svg", 
29				"title": "Reference", 
30				"url": "reference" 
31
32
33 
34	breadcrumbJSONArray = navigationJSONObject.getJSONArray("breadcrumb") 
35	childrenJSONArray = navigationJSONObject.getJSONArray("children") 
36	parentJSONObject = navigationJSONObject.getJSONObject("parent") 
37	productJSONObject = breadcrumbJSONArray.getJSONObject(breadcrumbJSONArray.length()-1)!navigationJSONObject.getJSONObject("self") 
38	siblingsJSONArray = navigationJSONObject.getJSONArray("siblings") 
39/> 
40 
41<div class="learn-article-nav"> 
42	<#if productJSONObject?has_content && productJSONObject.getString("title")?has_content && navigationMenuItems[productJSONObject.getString("title")]?has_content && navigationMenuItems[productJSONObject.getString("title")].title?has_content> 
43		<div 
44			class="dropdown learn-article-nav-root learn-dropdown" 
45
46			<div class="learn-article-nav-item"> 
47				<div class="d-flex"> 
48					<div class="learn-article-nav-image"> 
49						<img 
50							class="lexicon-icon lexicon-icon-caret-bottom product-icon" 
51							role="presentation" 
52							src='${navigationMenuItems[productJSONObject.getString("title")].image}' 
53							viewBox="0 0 512 512" 
54						/> 
55					</div> 
56 
57					<span class="learn-article-nav-text">${navigationMenuItems[productJSONObject.getString("title")].title}</span> 
58				</div> 
59 
60				<div id="dropdown-icon"> 
61					<svg 
62						class="lexicon-icon lexicon-icon-caret-bottom" 
63						role="presentation" 
64						viewBox="0 0 512 512" 
65
66						<use xlink:href="/o/admin-theme/images/clay/icons.svg#caret-bottom"></use> 
67					</svg> 
68				</div> 
69			</div> 
70 
71			<ul class="dropdown-menu learn-dropdown-menu"> 
72				<#list navigationMenuItems as key, value> 
73					<li> 
74						<a 
75							class="dropdown-item learn-article-nav-item" 
76							href="/w/${navigationMenuItems[key].url}/index" 
77							tabindex="4" 
78
79							<span class="d-flex"> 
80								<span class="learn-article-nav-image"> 
81									<img 
82										class="lexicon-icon lexicon-icon-caret-bottom product-icon mt-0 mr-2" 
83										role="presentation" 
84										src="${value.image}"height: 25px; margin-left: 5px; max-width: none; width: 25px; 
85										viewBox="0 0 512 512" 
86									/> 
87								</span> 
88								<span class="learn-article-nav-text">${value.title}</span> 
89							</span> 
90 
91							<#if navigationMenuItems[productJSONObject.getString("title")].url == value.url> 
92								<span> 
93									<@clay["icon"] symbol="check" /> 
94								</span> 
95							</#if> 
96						</a> 
97					</li> 
98				</#list> 
99			</ul> 
100		</div> 
101	</#if> 
102 
103	<div class="learn-article-nav-content"> 
104		<#if parentJSONObject?has_content && parentJSONObject.getString("url")?has_content> 
105			<div class="learn-article-nav-item learn-article-nav-parent liferay-nav-item p-2"> 
106				<div class="mr-2"> 
107					<a 
108						href='${parentJSONObject.getString("url")}' 
109
110						<svg 
111							class="lexicon-icon lexicon-icon-angle-left" 
112							role="presentation" 
113							viewBox="0 0 512 512" 
114
115							<use xlink:href="/o/admin-theme/images/clay/icons.svg#angle-left"></use> 
116						</svg> 
117					</a> 
118				</div> 
119 
120				<span>${parentJSONObject.getString("title")}</span> 
121			</div> 
122		</#if> 
123 
124		<#if childrenJSONArray.length() gt 0> 
125			<ul class="m-0 p-2"> 
126				<#list 0..childrenJSONArray.length()-1 as i> 
127					<li class="learn-article-nav-item"> 
128						<a 
129							class='liferay-nav-item ${(navigationJSONObject.getJSONObject("self").url == childrenJSONArray.getJSONObject(i).url)?then("selected", "")}' 
130							href="${childrenJSONArray.getJSONObject(i).url}" 
131
132							<span>${childrenJSONArray.getJSONObject(i).getString("title")}</span> 
133						</a> 
134					</li> 
135				</#list> 
136			</ul> 
137		<#elseif siblingsJSONArray.length() gt 0> 
138			<ul class="m-0 p-2"> 
139				<#list 0..siblingsJSONArray.length()-1 as i> 
140					<li class="learn-article-nav-item"> 
141						<a 
142							class='liferay-nav-item ${(navigationJSONObject.getJSONObject("self").url == siblingsJSONArray.getJSONObject(i).url)?then("selected", "")}' 
143							href="${siblingsJSONArray.getJSONObject(i).url}" 
144
145							<span>${siblingsJSONArray.getJSONObject(i).getString("title")}</span> 
146						</a> 
147					</li> 
148				</#list> 
149			</ul> 
150		</#if> 
151	</div> 
152</div> 

Elasticsearchのバックアップ

Elasticsearchレプリカ は 、ノードがダウンするのを防ぎますが、壊滅的な障害が発生した場合には役立ちません。 その時に役立つのは、適切なバックアップ習慣だけです。

アップグレード前のインデックスのバックアップ

たとえインデックスされたデータがLiferayのデータベースから再インデックスすることで復元できるとしても、すべてのアップグレードシナリオでインデックスのバックアップを取るのがベストプラクティスです。 アプリ固有のインデックスの スナップショットを取ること (Liferay DXP 7.2と7.3のLiferayの検索の調整インデックスのように)は、データが検索インデックスにのみ保存されている場合に必須となります。 スナップショットは、新しいElasticsearchサーバをセットアップする際に、以前のデータ(同義語セットや結果ランキングなど)を復元するために使用することができます。 このアプローチを試みる前に、 スナップショットとバージョンの復元の互換性 に関するElasticsearchのドキュメントを読んでください。

ここでは、代表的なアップグレードシナリオを紹介します。

  • Liferayとは無関係にElasticsearchクラスタをアップグレードする場合:すべてのインデックスのバックアップを推奨します。 スナップショットからのデータの復元は、すべてのインデックスがシステムに残っているため、必要ありません。
  • Liferayをアップグレードし、同じElasticsearchクラスタに接続する場合:すべてのインデックスのバックアップを行うことを推奨します。 スナップショットからのデータの復元は、すべてのインデックスがシステムに残っているため、必要ありません。
  • Liferayをアップグレードし、別のElasticsearchクラスタに接続する場合:すべてのインデックスのバックアップを推奨します。 スナップショットからのリストアは、すべてのプライマリストレージインデックスに必要です。 Liferayの検索の調整機能(結果ランキングと同義語セット)のいずれかを使用している場合、Liferay DXP 7.4へのアップグレード後に、 Liferayデータベースにインデックスデータをインポートする ことも必要です。

Elasticsearchクラスタのバックアップを作成する

tip

スナップショットの作成と管理は、 Kibana 7.x UI を使うと便利です。

次の3つの手順でElasticsearchクラスターをバックアップし、バックアップの復元をテストします。

  1. リポジトリを作成します

  2. Elasticsearchクラスターのスナップショットを作成します

  3. スナップショットから復元します

note

より詳細な情報については、Elastic社の Elasticsearch 管理ガイド を参照し、特に Snapshot and Restore モジュール を参照してください。

リポジトリの作成

まず、スナップショットを保存する リポジトリを作成 します。 Elasticsearch では、以下のようないくつかのリポジトリタイプを使用できます。

  • ネットワークファイルシステムやNASなどの共有ファイルシステム
  • Amazon S3
  • HDFS(Hadoop Distributed File System)
  • Azureクラウド
  • Google Cloud Storage

スナップショットを共有ファイルシステムに保存したい場合は、まず各ノードの elasticsearch.ymlpath.repo 設定を使用して共有ファイルシステムへのパスを登録します 。 例えば、

path.repo: ["path/to/shared/file/system/"]

リポジトリをホストするフォルダへのパスを登録した後(フォルダが存在することを確認してください)、PUTコマンドでリポジトリを作成します。 例えば、

PUT /_snapshot/test_backup
{
  "type": "fs",
  "settings": {
    "location": "/path/to/shared/file/system/"
  }
}'

test_backupを作成するリポジトリの名前に置き換え、location\の設定値を共有ファイルシステムへの絶対パスに置き換えます。

リポジトリが正しく作成されていれば、コマンドは次のような結果を返します。

{"acknowledged":true}

リポジトリが存在しているので、スナップショットを作成します。

クラスターのスナップショットを取得する

最も簡単なスナップショットのアプローチは、 クラスター内のすべてのインデックスのスナップショット を作成することです。 例えば、

PUT /_snapshot/test_backup/snapshot_1

スナップショットコマンドが成功すると、次の結果が返されます。

{"accepted":true}

スナップショットを特定のインデックスに制限することもできます。 たとえば、Liferay Enterprise Searchモニタリングを使用しているが、スナップショットからモニタリングインデックスを除外したい場合があります。 スナップショットに含めるインデックスを明示的に宣言できます。 例えば、

PUT /_snapshot/test_backup/snapshot_2
{ "indices": "liferay-0,liferay-20116" }

すべてのインデックスとそのメトリクスを一覧表示するには、このコマンドを実行します:

GET /_cat/indices?v

インデックスメトリクスの例:

health status index                                              uuid                   pri rep docs.count docs.deleted store.size pri.store.size
green  open   liferay-20101-search-tuning-rankings               ykbNqPjkRkq7aCYnc7G20w   1   0          7            0      7.7kb          7.7kb
green  open   liferay-20101-workflow-metrics-tokens              DF-1vq8IRDmFAqUy4MHHPQ   1   0          4            0       26kb           26kb
green  open   liferay-20101                                      QKXQZeV5RHKfCsZ-TYU-iA   1   0     253015          392     43.1mb         43.1mb
green  open   liferay-20101-workflow-metrics-sla-task-results    SrWzmeLuSKGaIvKrv4WmuA   1   0          4           72     30.6kb         30.6kb
green  open   liferay-20101-workflow-metrics-processes           Ras8CH0PSDGgWSyO3zEBhg   1   0          1            0     49.3kb         49.3kb
green  open   liferay-20101-workflow-metrics-nodes               bcdKKgDySeWf4BJnmMzk6A   1   0          4            0     10.5kb         10.5kb
green  open   liferay-20101-workflow-metrics-sla-process-results VJrNOpJWRoeTaJ-sBGs_vA   1   0          3           91     47.4kb         47.4kb
green  open   liferay-20101-workflow-metrics-instances           OgJMyD5ZQIi2h0xUTSjezg   1   0          3            0     62.4kb         62.4kb
green  open   liferay-0                                          jPIEOfZhSCKZSWnY0L65RQ   1   0     253114          491     50.1mb         50.1mb
green  open   liferay-20101-search-tuning-synonyms               pAUN8st1RmaV1NxXtj-Sig   1   0          1            0      4.1kb          4.1kb
note

Elasticsearchは、スマートスナップショットアプローチを採用しています。 その意味を理解するために、1つのインデックスを考えてみましょう。 最初のスナップショットにはインデックス全体のコピーが含まれ、それ以降のスナップショットには、最初の完全なインデックススナップショットと現在のインデックスの状態との差分のみが含まれます。

最終的には、リポジトリに多数のスナップショットが作成されることになります。スナップショットに名前を付けたとしても、スナップショットに含まれているものを忘れてしまう可能性があります。 Elasticsearch APIを使用して説明を取得できます。 例えば、

GET /_snapshot/test_backup/snapshot_1

以下が返されます

{"snapshots":[
    {"snapshot":"snapshot_1",
    "uuid":"WlSjvJwHRh-xlAny7zeW3w",
    "version_id":6.80399,
    "version":"6.8.2",
    "indices":["liferay-20099","liferay-0","liferay-47206"],
    "state":"SUCCESS",
    "start_time":"2018-08-15T21:40:17.261Z",
    "start_time_in_millis":1534369217261,
    "end_time":"2018-08-15T21:40:17.482Z",
    "end_time_in_millis":1534369217482,
    "duration_in_millis":221,
    "failures":[],
    "shards":{
        "total":3,
        "failed":0,
        "successful":3

        }
    }
]}

スナップショット情報には、インデックスの時間範囲が含まれています。

スナップショットを破棄したい場合は DELETE コマンドを使ってください。

DELETE /_snapshot/test_backup/snapshot_1

スナップショットにすべてのインデックスを含めると、多くの時間とストレージを消費する可能性があります。 間違ってスナップショットの作成を開始した場合(例えば、特定のインデックスでフィルタリングしたかったが、すべてのインデックスを含んでしまった場合)、DELETEコマンドを使用してスナップショット処理をキャンセルすることができます。 名前でスナップショットを削除すると、スナップショットプロセスが終了し、部分的なスナップショットがリポジトリから削除されます。

スナップショットからの復元のテスト

壊滅的な障害が発生した場合、スナップショットから 検索インデックスを復元 することができなければ、スナップショットは何の役にも立ちません。 すべてのスナップショットのインデックスをリストアするには _restore API を使用します:

POST /_snapshot/test_backup/snapshot_1/_restore

スナップショット・インデックスから既存のインデックスにデータをリストアする必要がある場合は、別の名前でインデックスをリストアしてから、既存のインデックスにデータを再インデックスします。 リストアコマンドを特定のインデックスに限定するには、indicesオプションを使用します。 rename_patternrename_replacement オプションを使用して、リストアしたインデックスの名前を変更する:

POST /_snapshot/test_backup/snapshot_1/_restore
{
    "indices": "liferay-20116",
    "rename_pattern": "(.+)",
    "rename_replacement": "restored-$1"
}

これはスナップショットからliferay-201616という名前のインデックスだけをリストアし、名前をrestored_liferay-201616に変更します。 いったんクラスタにリストアすると、_reindex API コールを使ってバックアップしたデータを既存の liferay-20116 インデックスにリストアすることができる。

POST _reindex/
{
    "dest": {
      "index": "liferay-20116"
    },
    "source": {
      "index": "restored_liferay-201116"
    }
}

スナップショット処理をキャンセルするのと同様に、DELETEコマンドを使って誤ったリストア処理をキャンセルすることができます:

DELETE /restored_liferay-20116index_3

本番環境システムでの壊滅的な障害は誰もが望みませんが、スナップショットを取得してインデックスを復元するためのElasticsearchのAPIを使用すれば、障害が発生した場合に検索クラスターを復元できるので安心です。 詳細とオプションについては、Elasticの スナップショットと復元のドキュメンテーション を参照してください。

Liferay 7.2と7.3の検索チューニングインデックスのバックアップと復元

Elasticsearchインデックスのスナップショットを作成することを強くお勧めします。プライマリストレージ形式として機能するインデックス(Liferay DXP 7.2および7.3の 同義語セット結果ランキング など)の場合は特にお勧めします。 データベースには、これらのアプリケーションのレコードはありません。

Elasticsearchの スナップショットおよび復元 機能を使用して、検索の調整インデックスをバックアップおよび復元できます。

  1. システムのどこかに elasticsearch_local_backup というフォルダを作成する。 Elasticsearchがそのフォルダ(例:/path/to/elasticsearch_local_backup)に読み書きできることを確認してください。

  2. 追加

    path.repo: [ "/path/to/elasticsearch_local_backup" ]
    

    elasticsearch.yml に追加してください。 Elasticsearch クラスタ内のすべてのマスターノードとデータノード です。 Elasticsearchをアップグレードする場合は、スナップショットリポジトリへのパスがアップグレード前とアップグレード後のElasticsearch構成で同じであることを確認してください。

  3. すべてのElasticsearchノードを再起動します。

  4. スナップショットリポジトリを登録します 。 以下の snapshot API リクエストを実行することができる(例えば Kibana の Dev Tools コンソールから):

    PUT /_snapshot/elasticsearch_local_backup
    {
      "type": "fs",
      "settings": {
        "location": "/path/to/elasticsearch_local_backup"
      }
    }
    
    

    新しいElasticsearchバージョンにアップグレードする場合は、アップグレード後のElasticsearchでこれと同じコマンドを使用して、スナップショットリポジトリを登録できます。

  5. スナップショットを作成します

    PUT /_snapshot/elasticsearch_local_backup/snapshot1?wait_for_completion=true
    {
      "indices": "liferay-20101-search-tuning*",
      "ignore_unavailable": true,
      "include_global_state": false
    }
    

    すべてのLiferayインデックスのスナップショットを作成したい場合は、代わりに"indices":"liferay*,workflow-metrics*" を使用することができます。 アップグレードシナリオを使用している場合は、Liferay DXP 7.2および7.3の同義語セットインデックスや結果ランキングインデックスなど、データベースから再作成できないインデックスのみのスナップショットを作成するほうが合理的な場合があります。

  6. リストア 特定のインデックスを別の名前でスナップショットからリストアするには、以下のような restore APIコールを実行する:

    POST /_snapshot/elasticsearch_local_backup/snapshot1/_restore
    {
      "indices": "liferay-20101-search-tuning-synonyms,liferay-20101-search-tuning-rankings",
      "ignore_unavailable": true,
      "include_global_state": false,
      "rename_pattern": "(.+)",
      "rename_replacement": "restored_$1",
      "include_aliases": false
    }
    

    ここで indices はリストア元のスナップショットされたインデックス名を指定する。 上記の呼び出しによるインデックスは、rename_patternrename_replacement の正規表現に従って、restored_liferay-20101-search-tuning-rankingsrestored_liferay-20101-search-tuning-synonyms としてリストアされる。

Sidecar/Embeddedモードで実行中に検索チューニング設定(シノニムセットや結果ランキングなど)を追加した場合、Elasticsearchへの本番モード接続を設定し、インデックスを再作成すると、それらは消えてしまいます。

既存の検索チューニング・インデックス・ドキュメントをリストアするには、Elasticsearchの Reindex API を使います:

POST _reindex/
{
 "dest": {
   "index": "liferay-20101-search-tuning-synonyms"
 },
 "source": {
   "index": "restored_liferay-20101-search-tuning-synonyms"
 }
}

liferay-20101-search-tuning-rankingsインデックスに対して同じコマンドを実行する。 アップグレード後のElasticsearchインストールで両方のリクエストを実行すると、アップグレード前のシステムから同義語セットと結果ランキングのデータが復元されるようになりました。

検索の調整インデックス名

すぐに使用できる検索の調整インデックス名は、Liferayのバージョンとパッチレベルによって異なります。

Liferayのバージョンとパッチ検索の調整インデックス
Liferay DXP 7.2 SP2/FP5以下liferay-search-tuning-rankings
liferay-search-tuning-synonyms-liferay-<companyId>
Liferay DXP 7.2 SP3/FP8以降liferay-<companyId>-search-tuning-rankings
liferay-<companyId>-search-tuning-synonyms
Liferay DXP 7.3 GA1+ および7.4 GA1+liferay-<companyId>-search-tuning-rankings
liferay-<companyId>-search-tuning-synonyms

<companyId>(例:20101)はデータベース内の指定されたCompanyレコードに属する。 UIでは Instance ID と表示され、 仮想インスタンス を表します。

次のステップ

Elasticsearchをアップグレード する場合は、今すぐアップグレードできます。

関連トピック

検索管理およびチューニング