Das Januar Release hat viele Breaking-Changes. Bitte die Anleitung sorgfältig durchgehen.
Allgemein
Der Goobi viewer benötigt jetzt Java 21, Tomcat 10 und Solr 9.8.0. Die folgenden Punkte beziehen sich auf ein System, das von Ubuntu Linux Server 22.04 auf 24.04 aktualisiert wurde. Bei alternativen Distributionen sind die Schritte entsprechend der dortigen Pfade und Befehle anzupassen.
Java
Der Goobi viewer läuft jetzt mit Java 21. Dafür sicherstellen, dass das entsprechende Paket installiert und diese Version auch in Verwendung ist:
patch /etc/default/tomcat10 << "EOF"
@@ -6,11 +6,20 @@
# You may pass JVM startup parameters to Java here. If you run Tomcat with
# Java 8 instead of 9 or newer, add "-XX:+UseG1GC" to select a suitable GC.
# If unset, the default options will be: -Djava.awt.headless=true
-JAVA_OPTS="-Djava.awt.headless=true"
+#JAVA_OPTS="-Djava.awt.headless=true"
# To enable remote debugging uncomment the following line.
# You will then be able to use a Java debugger on port 8000.
#JAVA_OPTS="${JAVA_OPTS} -agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=n"
+JAVA_OPTS="-Djava.awt.headless=true -Xmx4g -Xms4g"
+JAVA_OPTS="${JAVA_OPTS} -XX:+UseG1GC"
+JAVA_OPTS="${JAVA_OPTS} -XX:+ParallelRefProcEnabled"
+JAVA_OPTS="${JAVA_OPTS} -XX:+DisableExplicitGC"
+JAVA_OPTS="${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom"
+JAVA_OPTS="${JAVA_OPTS} -Dfile.encoding='utf-8'"
+JAVA_OPTS="${JAVA_OPTS} --add-exports=java.desktop/sun.awt.image=ALL-UNNAMED"
+
+UMASK=0022
# Java compiler to use for translating JavaServer Pages (JSPs). You can use all
# compilers that are accepted by Ant's build.compiler property.
@@ -20,4 +29,4 @@
#SECURITY_MANAGER=true
# Whether to compress logfiles older than today's
-#LOGFILE_COMPRESS=1
+LOGFILE_COMPRESS=1
EOF
patch /etc/tomcat10/context.xml << "EOF"
@@ -28,4 +28,7 @@
<!--
<Manager pathname="SESSIONS.ser" />
-->
+
+ <!-- Set mode for the JSESSONID cookie. Google authentication needs "lax" -->
+ <CookieProcessor sameSiteCookies="strict" />
</Context>
EOF
patch /etc/tomcat10/server.xml << "EOF"
@@ -65,49 +65,22 @@
AJP Connector: /docs/config/ajp.html
Define a non-SSL/TLS HTTP/1.1 Connector on port 8080
-->
- <Connector port="8080" protocol="HTTP/1.1"
- connectionTimeout="20000"
- redirectPort="8443"
- maxParameterCount="1000"
- />
- <!-- A "Connector" using the shared thread pool-->
- <!--
- <Connector executor="tomcatThreadPool"
- port="8080" protocol="HTTP/1.1"
- connectionTimeout="20000"
- redirectPort="8443"
- maxParameterCount="1000"
- />
- -->
- <!-- Define an SSL/TLS HTTP/1.1 Connector on port 8443 with HTTP/2
- This connector uses the NIO implementation. The default
- SSLImplementation will depend on the presence of the APR/native
- library and the useOpenSSL attribute of the AprLifecycleListener.
- Either JSSE or OpenSSL style configuration may be used regardless of
- the SSLImplementation selected. JSSE style configuration is used below.
- -->
- <!--
- <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
- maxThreads="150" SSLEnabled="true"
- maxParameterCount="1000"
- >
- <UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
- <SSLHostConfig>
- <Certificate certificateKeystoreFile="conf/localhost-rsa.jks"
- type="RSA" />
- </SSLHostConfig>
- </Connector>
- -->
- <!-- Define an AJP 1.3 Connector on port 8009 -->
- <!--
- <Connector protocol="AJP/1.3"
- address="::1"
- port="8009"
- redirectPort="8443"
- maxParameterCount="1000"
- />
- -->
+ <Connector address="127.0.0.1" port="8080" protocol="HTTP/1.1"
+ server=" "
+ connectionTimeout="20000"
+ maxThreads="400"
+ URIEncoding="UTF-8"
+ enableLookups="false"
+ disableUploadTimeout="true"
+ proxyName="VIEWER.EXAMPLE.ORG"
+ proxyPort="80" />
+
+ <Connector address="127.0.0.1" port="8009" protocol="AJP/1.3"
+ secretRequired="false"
+ connectionTimeout="20000"
+ maxThreads="400"
+ URIEncoding="UTF-8" />
<!-- An Engine represents the entry point (within Catalina) that processes
every request. The Engine implementation for Tomcat stand alone
@@ -150,9 +123,14 @@
<!-- Access log processes all example.
Documentation at: /docs/config/valve.html
Note: The pattern used is equivalent to using pattern="common" -->
+ <!--
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
+ -->
+ <Valve className="org.apache.catalina.valves.CrawlerSessionManagerValve"
+ crawlerUserAgents=".*[bB]ot.*|.*Yahoo! Slurp.*|.*Feedfetcher-Google.*|.*Apache-HttpClient.*|.*[Ss]pider.*|.*[Cc]rawler.*|.*nagios.*|.*Yandex.*|.*facebookexternalhit.*|.*bytedance.com.*|.*Turnitin.*|.*GoogleOther.*|.*python-requests.*|.*check_http.*"
+ sessionInactiveInterval="60"/>
</Host>
</Engine>
EOF
Nun die zum Goobi viewer dazugehörige Konfigurationsdatei übernehmen:
Zu diesem Zeitpunkt muss eine aktualisierte, neue viewer.war mit dem 25.01 Release vorliegen, da eine ältere Version des Goobi viewers im Tomcat 10 nicht mehr startet.
Sofern auf dem System der Bash Alias cata gesetzt ist, muss der auf den neuen Pfad beziehungsweise die neue Unitfile angepasst werden.
Zuletzt noch sicherstellen, dass für den Benutzeraccount tomcatder richtige Pfad zum Homeverzeichnis gesetzt ist und - sofern vorhanden - das entsprechende .ssh Verzeichnis verschieben:
Die Konfigurationsdatei des Indexers muss an die vereinfachte XPATH-Konfiguration angepasst werden. Dafür können die folgenden Befehle und Skript verwendet werden:
Sofern im Goobi viewer die Statistikfunktionalität aktiviert ist, werden die jetzt erzeugten JSON Dateien nach der Indexierung nicht mehr gelöscht, sondern in einen indexed_statistics Ordner gelegt. Dafür muss das Verzeichnis angelegt und eine zusätzliche Zeile in die config_indexer.xml eingetragen werden:
Damit bei dem Solr Update keine indexierten Statistiken verloren gehen, müssen diese aus dem Suchindex extrahiert und als JSON Dateien im Dateisystem abgelegt werden. Mit der folgenden Abfrage kann ermittelt werden, ob die Migration notwendig ist. Das ist der Fall, wenn die Ausgabe einen Wert größer 0 enthält:
Wenn eine Migration stattfinden muss, dann kann dafür das folgende Skript verwendet werden:
migrate_statistics.py
import json
import requests
from datetime import datetime
from collections import defaultdict
# Solr URL and query parameters
SOLR_URL = "http://localhost:8983/solr/collection1/select"
QUERY = "DOCTYPE:STATISTICS_USAGE"
ROWS = 1000
def query_solr(url, query, rows):
"""
Query Solr and return the response JSON.
"""
params = {
"q": query,
"rows": rows,
"wt": "json"
}
response = requests.get(url, params=params)
if response.status_code != 200:
raise Exception(f"Solr query failed: {response.status_code} - {response.text}")
return response.json()
def create_json_structure(docs):
"""
Group documents by date and create the desired JSON structure.
"""
grouped_data = defaultdict(list)
# Group documents by date
for doc in docs:
date = doc.get("STATISTICS_DATE", "").split("T")[0] # Extract date part
if not date:
continue # Skip documents without a valid date
viewer_name = doc.get("STATISTICS_VIEWERNAME", "unknown")
for key, value in doc.items():
if key.startswith("STATISTICS_RECORD_"):
record_id = key.replace("STATISTICS_RECORD_", "")
grouped_data[date].append({
"counts": value[:4], # Use only the first 4 values
"pi": record_id
})
# Create JSON structure for each date
json_files = {}
for date, records in grouped_data.items():
json_files[date] = {
"date": date,
"records": records,
"viewer-name": viewer_name # Use the last viewer name encountered
}
return json_files
def save_json_to_file(json_data, filename):
"""
Save JSON data to a file.
"""
with open(filename, "w") as f:
json.dump(json_data, f, indent=4)
def main():
# Query Solr
print(f"Querying Solr at {SOLR_URL}...")
solr_response = query_solr(SOLR_URL, QUERY, ROWS)
# Process the Solr response
docs = solr_response.get("response", {}).get("docs", [])
if not docs:
print("No documents found.")
return
# Create JSON structure grouped by date
json_files = create_json_structure(docs)
# Save JSON files
for date, json_data in json_files.items():
filename = f"statistics-usage-{date}.json"
save_json_to_file(json_data, filename)
print(f"Created JSON file: {filename}")
if __name__ == "__main__":
main()
Das kann in dem folgenden Ordner abgelegt, einmalig aufgerufen und danach wieder gelöscht werden:
cd /opt/digiverso/viewer/indexed_statistics/
vim migrate_statistics.py
python3 migrate_statistics.py
rm migrate_statistics.py
Zookeeper
In der /etc/zookeeper/conf/zoo.cfg sicherstellen, dass das dataDir auf den richtigen Pfad zeigt und die clientPortAddress auf localhost gesetzt ist:
Sollte Zookeeper jetzt nicht starten, kann es sein, dass noch eine Snapshot-Datei benötigt wird:
# Prüfen ob Datei vorhanden ist
ll /var/lib/zookeeper/version-2/snapshot.0
# Wenn nicht, dann ablegen
wget -O /var/lib/zookeeper/version-2/snapshot.0 https://issues.apache.org/jira/secure/attachment/12928686/snapshot.0
chown zookeeper: /var/lib/zookeeper/version-2/snapshot.0
Solr
Mit dem 25.01 Release wird auf eine aktuelle Solr Version aktualisiert werden. Die hier festgehaltenen Schritte sind als Anleitung zu verstehen bei denen die Schritte im Einzelnen durchgespielt und bei Bedarf an lokale Pfade und Gegebenheiten angepasst werden müssen.
# Stop Solr Service and create Backup
systemctl stop solr
mkdir /root/BACKUP/$(date -I)
cd /opt/digiverso/
tar -czf /root/BACKUP/$(date -I)/solr.tar.gz solr/
mv /opt/digiverso/solr/log4j2.xml /root/BACKUP/$(date -I)/
grep ^SOLR_HEAP /etc/default/solr.in.sh # remind for later ;-)
mv /etc/default/solr.in.sh /root/BACKUP/$(date -I)/
# Download and Install
cd /tmp
wget https://archive.apache.org/dist/solr/solr/9.8.0/solr-9.8.0.tgz
tar -xzf solr-9.8.0.tgz solr-9.8.0/bin/install_solr_service.sh --strip-components=2
./install_solr_service.sh solr-9.8.0.tgz -d /opt/digiverso/solr -i /opt/digiverso/solr -p 8983 -s solr -u solr -f -n
patch /etc/default/solr.in.sh << "EOF"
@@ -32,7 +32,7 @@
#SOLR_START_WAIT="$SOLR_STOP_WAIT"
# Increase Java Heap as needed to support your indexing / query needs
-#SOLR_HEAP="512m"
+SOLR_HEAP="2048m"
# Expert: If you want finer control over memory options, specify them directly
# Comment out SOLR_HEAP if you are using this though, that takes precedence
@@ -50,25 +50,19 @@
# -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+PrintTenuringDistribution -XX:+PrintGCApplicationStoppedTime"
# These GC settings have shown to work well for a number of common Solr workloads
-#GC_TUNE=" \
-#-XX:+ExplicitGCInvokesConcurrent \
-#-XX:SurvivorRatio=4 \
-#-XX:TargetSurvivorRatio=90 \
-#-XX:MaxTenuringThreshold=8 \
-#-XX:+UseConcMarkSweepGC \
-#-XX:ConcGCThreads=4 -XX:ParallelGCThreads=4 \
-#-XX:+CMSScavengeBeforeRemark \
-#-XX:PretenureSizeThreshold=64m \
-#-XX:+UseCMSInitiatingOccupancyOnly \
-#-XX:CMSInitiatingOccupancyFraction=50 \
-#-XX:CMSMaxAbortablePrecleanTime=6000 \
-#-XX:+CMSParallelRemarkEnabled \
-#-XX:+ParallelRefProcEnabled etc.
+GC_TUNE=" \
+-XX:+ExplicitGCInvokesConcurrent \
+-XX:SurvivorRatio=4 \
+-XX:TargetSurvivorRatio=90 \
+-XX:MaxTenuringThreshold=8 \
+-XX:ConcGCThreads=4 -XX:ParallelGCThreads=4 \
+-XX:PretenureSizeThreshold=64m \
+-XX:+ParallelRefProcEnabled"
# Set the ZooKeeper connection string if using an external ZooKeeper ensemble
# e.g. host1:2181,host2:2181/chroot
# Leave empty if not using SolrCloud
-#ZK_HOST=""
+ZK_HOST="127.0.0.1:2181"
# Set to true if your ZK host has a chroot path, and you want to create it automatically.
#ZK_CREATE_CHROOT=true
@@ -129,7 +123,7 @@
# Changes the logging level. Valid values: ALL, TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF. Default is INFO
# This is an alternative to changing the rootLogger in log4j2.xml
-#SOLR_LOG_LEVEL=INFO
+SOLR_LOG_LEVEL=ERROR
# Location where Solr should write logs to. Absolute or relative to solr start dir
#SOLR_LOGS_DIR=logs
@@ -293,7 +287,7 @@
# SOLR_OPTS="$SOLR_OPTS -Dlog4j2.formatMsgNoLookups=true"
# The bundled plugins in the "modules" folder can easily be enabled as a comma-separated list in SOLR_MODULES variable
-# SOLR_MODULES=extraction,ltr
+SOLR_MODULES=analysis-extras
# Configure the default replica placement plugin to use if one is not configured in cluster properties
# See https://solr.apache.org/guide/solr/latest/configuration-guide/replica-placement-plugins.html for details
EOF
# Copy old configset and create new one:
cp -a /opt/digiverso/solr/solr-9.5.0/server/solr/configsets/goobiviewer /opt/digiverso/solr/solr-9.8.0/server/solr/configsets/
cp -a /opt/digiverso/solr/solr-9.5.0/server/solr/configsets/goobiviewer /opt/digiverso/solr/solr-9.8.0/server/solr/configsets/goobiviewer_25.01
cp /opt/digiverso/solr/solr-9.8.0/server/solr/configsets/_default/conf/solrconfig.xml /opt/digiverso/solr/solr-9.8.0/server/solr/configsets/goobiviewer_25.01/conf/
patch /opt/digiverso/solr/solr-9.8.0/server/solr/configsets/goobiviewer_25.01/conf/solrconfig.xml << "EOF"
@@ -36,6 +36,7 @@
affect both how text is indexed and queried.
-->
<luceneMatchVersion>9.11</luceneMatchVersion>
+ <schemaFactory class="ClassicIndexSchemaFactory"/>
<!-- Data Directory
@@ -629,7 +630,7 @@
<!-- Shared parameters for multiple Request Handlers -->
<initParams path="/update/**,/query,/select,/spell">
<lst name="defaults">
- <str name="df">_text_</str>
+ <str name="df">DEFAULT</str>
</lst>
</initParams>
@@ -907,7 +908,7 @@
<!-- The update.autoCreateFields property can be turned to false to disable schemaless mode -->
- <updateRequestProcessorChain name="add-unknown-fields-to-the-schema" default="${update.autoCreateFields:true}"
+ <updateRequestProcessorChain name="add-unknown-fields-to-the-schema" default="${update.autoCreateFields:false}"
processor="uuid,remove-blank,field-name-mutating,max-fields,parse-boolean,parse-long,parse-double,parse-date,add-schema-fields">
<processor class="solr.LogUpdateProcessorFactory"/>
<processor class="solr.DistributedUpdateProcessorFactory"/>
EOF
wget -O /opt/digiverso/solr/solr/server/solr/configsets/goobiviewer_25.01/conf/schema.xml https://raw.githubusercontent.com/intranda/goobi-viewer-indexer/master/goobi-viewer-indexer/src/main/resources/other/schema.xml
chown solr: /opt/digiverso/solr/solr/server/solr/configsets/goobiviewer_25.01/conf/schema.xml
cd /opt/digiverso/solr/solr/server/solr-webapp/webapp/WEB-INF/lib/
wget https://github.com/locationtech/jts/releases/download/1.17.0/jts-core-1.17.0.jar
chown solr: jts-core-1.17.0.jar
## ACHTUNG - PRÜFEN OB NOCH EIN ALTER SOLR PROZESS LÄUFT UND GGFS STOPPEN ##
systemctl start solr
cd /opt/digiverso/solr/solr
chmod 755 bin/solr
sudo -u solr bin/solr zk upconfig --solr-url "http://localhost:8983" -n goobiviewer -d server/solr/configsets/goobiviewer/
sudo -u solr bin/solr zk upconfig --solr-url "http://localhost:8983" -n goobiviewer_25.01 -d server/solr/configsets/goobiviewer_25.01/
sudo -u solr bin/solr create -c collection_25.01 -n goobiviewer_25.01
curl "http://localhost:8983/solr/admin/collections?action=CREATEALIAS&name=current&collections=collection_25.01&wt=xml"
Jetzt muss der Indexer angepasst werden. Dabei muss der Wert von <solrUrl /> auf den Alias der neuen Collection gesetzt, und der Wert von <oldSolrUrl /> die URL der bisherigen <solrUrl /> enthalten. Beispiel:
<!-- Example -->
<solrUrl>http://localhost:8983/solr/current</solrUrl>
<oldSolrUrl>http://localhost:8983/solr/collection1</oldSolrUrl>
Nun alle Daten aus den indexed_* Ordnern in den Hotfolder kopieren, zum mit dem folgenden Kommando:
Sobald die Neuindexierung abgeschlossen ist, muss in der config_viewer.xml ebenfalls die solrUrl auf den neuen Alias geändert werden.
XSLT
Das XSLT für das Filtern der METS Dateien wurde angepasst, so dass die fileGrp PRESENTATION ebenfalls herausgefiltert wird. Außerdem ist die Datei umbenannt worden: