Contents Menu Expand Light mode Dark mode Auto light/dark, in light mode Auto light/dark, in dark mode Skip to content
CrafterCMS v4.3.1
Light Logo Dark Logo
  • current
  • v4.1
  • v4.0
  • v3.1
  • Getting Started
    • Your First Project (headless)
    • Your First Project (templated)
  • Documentation by Role
    • Architects
    • Developer
      • Content Modeling
        • Form Section Control
        • Repeating Group Control
        • Input Control
        • Numeric Input Control
        • Text Area Control
        • Rich Text Editor Control
        • Dropdown Control
        • Date/Time Control
        • Time Control
        • Checkbox Control
        • Grouped Checkboxes Control
        • Item Selector Control
        • Image Control
        • Video Control
        • Transcoded Video Control
        • Label Control
        • Page Order Control
        • Filename Control
        • Auto Filename Control
        • Internal Name Control
        • Locale Selector Control
        • Components Data Source
        • Shared Content Data Source
        • Embedded Content Data Source
        • Image Uploaded from Desktop Data Source
        • Image from Repository Data Source
        • File Uploaded from Desktop Data Source
        • File Browse Data Source
        • File from WebDAV Repository Data Source
        • Image from WebDAV Repository Data Source
        • Video from WebDAV Repository Data Source
        • WebDAV File Upload Data Source
        • WebDAV Image Upload Data Source
        • WebDAV Video Upload Data Source
        • S3 Repository Data Source
        • Image from S3 Repository Data Source
        • Video from S3 Repository Data Source
        • S3 File Upload Data Source
        • S3 Image Upload Data Source
        • S3 Video Upload Data Source
        • Video Upload then Transcode from S3 using MediaConvert Data Source
        • Video Uploaded from Desktop Data Source
        • Video from Repository Data Source
        • Static Key Value Pairs Data Source
        • Simple Taxonomy Data Source
        • Audio Uploaded from Desktop Data Source
        • Audio from Repository Data Source
      • Information Architecture
      • Content Inheritance
      • Content Retrieval APIs
      • Static Content Access
      • Experience Builder (XB)
      • Security (Delivery)
      • Scheduled Jobs
      • Page and Component Controllers
      • Targeting
      • Servlet Filters
      • Working with Dates and Time Zones in Groovy
      • Working with Sass
      • Multi-environment Support
      • Custom Error Pages
      • Adding a New Language
      • Localization
      • Environment Variables Access
      • Adding a Default Screenshot to a Project/Site
      • Templating
        • Working with Dates and Time Zones in FreeMarker
      • Composable
        • Blueprints
        • Plugins
          • Crafter Studio Sidebar Plugin Example
          • Crafter Studio Experience Builder Plugin Example
          • Crafter Studio Toolbar Plugin Example
          • Crafter Studio Dashboard Plugin Example
          • Crafter Studio Project Tools Plugin Example
          • Crafter Studio Navigation Menu Plugin Example
          • Building Form Engine Control Project Plugins
          • Building Form Engine Data Source Project Plugins
          • Crafter Studio Full Screen Plugin Example
        • Crafter Marketplace
      • DevContentOps
      • Working in Your IDE
      • Upgrade
      • Security
      • Logging
    • Author
    • Project (Site) Administration
      • Configuring Publishing to Staging Target
      • Multi-environment Support
      • Project Tools
        • Viewing Logs Through Crafter Studio
        • Workflow States
        • Publishing Status
        • Git
        • Plugin Management
    • System Administrator
      • Installation
      • Configuration
      • Security
      • Performance and Scaling
      • Maintenance
        • Backup and Restore
        • Logging
        • Troubleshooting CrafterCMS
        • Reindexing Content for Search and Queries
          • Reindexing Content Without Disrupting Service in Production
      • Upgrading CrafterCMS
        • Upgrading CrafterCMS on a Server
        • Upgrading CrafterCMS on Docker/Kuber
        • Upgrading Studio Cluster
        • Upgrading Search
      • Disaster Recovery
  • Reference
    • Crafter Studio
    • Crafter Engine
    • Crafter Deployer
    • Crafter CLI
    • Crafter Profile
    • Crafter Social
    • FreeMarker (Templating) API
    • JavaScript SDK
    • GraphQL
    • Search
    • REST Content Retrieval APIs
    • Groovy/Java API
  • Security
    • Security Advisories
    • Security Policies
    • Security Processes
  • Accessibility
  • Roadmap
  • Support
  • Release Notes
  • Contribute
    • Documentation Standards
    • Open Source Acknowledgements
  • FAQ
  • »
  • Documentation by Role »
  • System Administrator »
  • Upgrading CrafterCMS »
  • Upgrading Search

  • Document Up to Date
  • Updated For 4.2.0
Back to top
Edit this page

Upgrading Search¶

Starting version 4.1.0, CrafterCMS now uses OpenSearch. This section describes how to upgrade search for CrafterCMS installed on a server.

Please read through the upgrade instructions here first. The steps for upgrading to OpenSearch follows almost exactly the same steps as listed in that document.

Important

Remember to manually shut down and backup CrafterCMS before beginning your upgrades!


Upgrading 3.1.x -> 4.2.0 (from ES 6.x)¶

To upgrade your 3.1.x installation, we’ll be running the upgrade scripts from a new binary archive. We’ll use the upgrade-search.sh script, which will update the data in place. This script tells the search engine to re-index internally to the new format and should only be run on CrafterCMS 3.1.x installs. Please backup your data directory before running the script.

Here is the upgrade-search script params:

 -h,--help                                  Show usage information
    --port <port>                           Elasticsearch port to use for
                                            upgrade ES temporary instance
    --status-retries <max status retries>   How many times to try to get a
                                            yellow status from the ES
                                            cluster (waiting 10s between
                                            retries)
    --status-timeout <seconds>              Timeout in seconds for the
                                            status check of the ES cluster
    --stay-alive                            Set to true to keep the
                                            process alive after reindexing
                                            is complete. This allows to
                                            query the ES server and
                                            review.
e.g:

# Run in a different port
./upgrade-search.sh --port 9206 /path/of/install/to/be/upgraded --stay-aliveUpgrading 3.1.x -> 4.1.0 (from ES 6.x)

Here are the steps to upgrade your CrafterCMS 3.1.x install:

  1. Download the CrafterCMS version you’d like to upgrade to, and extract the files.

  2. Configure the root directory of the new bundle to use Java version 17 (This is required to run the upgrade-search.sh script since ES 7 won’t run with Java 21)

  3. Run the upgrade-search.sh script from your newly extracted files.

    Run the upgrade-search script¶
    ./bin/upgrade/upgrade-search.sh /path/of/install/to/be/upgraded --stay-alive
    ========================================================================
    Search upgrade started
    ========================================================================
    ...
    End process. Stop Elasticsearch
    Move indexes from 'data/indexes-es' to 'indexes'
    ========================================================================
    Search upgrade completed
    ========================================================================
    
  4. Configure the root directory back to Java version 21

  5. Upgrade using the upgrade-target.sh script. We’ll need to upgrade the target without backing up the bin folder. This is because the MariaDB version is now 11 for 4.2.0, and we cannot start the old MariaDB from the new bundle. Please manually back it up before running the upgrade-target.sh script. Remember to enter No when prompted by the script Backup the bin folder before upgrade? [(Y)es/(N)o]:

    Run the upgrade-target script¶
    ./bin/upgrade/upgrade-target.sh /path/of/install/to/be/upgraded
    ...
    > Backup the bin folder before upgrade? [(Y)es/(N)o]:n
    ...
    ========================================================================
    Upgrade completed
    ========================================================================
    !!! Please read the release notes and make any necessary manual changes, then run the post upgrade script: /path/of/install/to/be/upgraded/bin/upgrade/post-upgrade.sh !!!
    
  6. Run the post-upgrade.sh script from the install that’s being upgraded. This will start CrafterCMS and ask for a signal to continue, then recreate search indexes. Remember to read the release notes or any relevant upgrade articles and make any necessary manual changes before running the post-upgrade.sh script. You’ll need to configure the installation root directory to use Java version 21 before running the script.

    Run the post-upgrade script¶
    cd /path/of/install/to/be/upgraded/bin/upgrade/
    ./post-upgrade.sh
    ========================================================================
    Post-upgrade 3.1.30 -> 4.2.0
    ========================================================================
    ...
    Please make sure Crafter has started successfully before continuing
    > Continue? [(Y)es/(N)o]: y
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Re-creating Search indexes for sites
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    WARNING: This will delete the current Search site indexes and recreate them.
    This is necessary because of a major Search upgrade. Don't proceed
    if you can't have any search downtime.
    > Proceed? [(Y)es/(N)o]: y
    ...
    ========================================================================
    Post-upgrade completed
    ========================================================================
    Crafter has already been started, you can use the system again
    

    The script will prompt you to check that CrafterCMS has started successfully before proceeding as noted above. To do this, monitor the tomcat logs and check for the line like below to make sure CrafterCMS has started (this could take a while because of the upgrade manager (UM) updates):

    27-Jun-2024 08:14:11.119 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in [127790] milliseconds
    

    Once the post-upgrade script is done, all indices should be now available in OpenSearch and CrafterCMS is now ready for use.


Upgrading 4.0.x -> 4.2.0 (from ES 7.15)¶

When upgrading from 4.0.x (running ES 7) the indices are not compatible at all, so the content needs to be reprocessed and indices rebuilt completely. The rebuilding of the indices is handled by the post-upgrade.sh script. Remember that the upgrade-search.sh script should NOT be run when upgrading your CrafterCMS 4.0.x install.

To upgrade your 4.0.x installation, we’ll be running the upgrade scripts from a new binary archive. Here are the steps:

  1. Download the CrafterCMS version you’d like to upgrade to, and extract the files.

  2. Upgrade using the upgrade-target.sh script from your newly extracted files:

    Run the upgrade-target script¶
    ./upgrade-target.sh /path/of/install/to/be/upgraded
    
  3. Run the post-upgrade.sh script. You’ll need to configure the installation root directory to use Java version 21 before running the script. This will:

    • Remove old data/indexes-es directory (old indexes are not usable by OpenSearch)

    • Start CrafterCMS and ask for signal to continue

    • Once started and CrafterCMS is up (including UM execution), let the post-upgrade continue by typing Y:

      Please make sure Crafter has started successfully before continuing
      > Continue? [(Y)es/(N)o]:
      
    • Post-upgrade will continue to trigger the reindex of all targets by calling the Deployer API /api/1/target/deploy-all

  4. Monitor the Deployer logs and wait for the reindex to be completed. You should see a message like the following:

    2024-04-20 14:36:46.050  INFO 376430 --- [deployment-1] org.craftercms.deployer.impl.TargetImpl  : Deployment for editorial110-authoring finished in 9.953 secs
    


Upgrading 4.1.x -> 4.2.0¶

There are no extra steps required for upgrading your 4.1.x install to 4.2.0, simply follow the instructions here. Remember that the upgrade-search.sh script should NOT be run when upgrading your CrafterCMS 4.1.x install.


Manual Updates for Search¶

The Upgrade Manager (UM) performs most of the updates required to upgrade your project to OpenSearch, such as the import updates in your classes. There are some instances where manual updates may need to be performed like below:

Updating Search Beans¶

If you have an application context that injects Elasticsearch like below, it will need to be updated to inject OpenSearch:

Application context that injects Elasticsearch¶
<beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="demoProfileService" class="com.demo.services.ProfileService" />

    <bean id="demoSearchService" class="com.demo.services.SearchService">
        <property name="elasticsearch" ref="crafter.elasticsearchService" />
        <property name="urlTransformationService" ref="crafter.urlTransformationService" />
    </bean>
</beans>

To update to OpenSearch, in the example above, the property is called elasticsearch and will need to be renamed. In the example below, the property has been renamed to searchClient:

Application context injection updated to OpenSearch¶
<beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="demoProfileService" class="com.demo.services.ProfileService" />

    <bean id="demoSearchService" class="com.demo.services.SearchService">
        <property name="searchClient" ref="crafter.searchClient" />
        <property name="urlTransformationService" ref="crafter.urlTransformationService" />
    </bean>
</beans>

Here’s a sample Groovy script that executes a search query in a project created using the Website Editorial blueprint:

Sample search query Groovy script.
  1package org.craftercms.sites.editorial
  2
  3import org.opensearch.client.opensearch._types.query_dsl.BoolQuery
  4import org.opensearch.client.opensearch._types.query_dsl.Query
  5import org.opensearch.client.opensearch._types.query_dsl.TextQueryType
  6import org.opensearch.client.opensearch.core.SearchRequest
  7import org.apache.commons.lang3.StringUtils
  8import org.craftercms.engine.service.UrlTransformationService
  9import org.craftercms.search.opensearch.client.OpenSearchClientWrapper
 10
 11class SearchService {
 12
 13    static final String ARTICLE_CONTENT_TYPE = "/page/article"
 14    static final List<String> ARTICLE_SEARCH_FIELDS = [
 15            'subject_t^1.5',
 16            'sections_o.item.section_html^1.0'
 17    ]
 18
 19    OpenSearchClientWrapper searchClient
 20    UrlTransformationService urlTransformationService
 21
 22    SearchService(OpenSearchClientWrapper searchClient, UrlTransformationService urlTransformationService) {
 23        this.searchClient = searchClient
 24        this.urlTransformationService = urlTransformationService
 25    }
 26
 27    def search(userTerm) {
 28        def query = new BoolQuery.Builder()
 29
 30        // Filter by content-type
 31        query.filter(q -> q
 32                .match(m -> m
 33                        .field("content-type")
 34                        .query(v -> v
 35                                .stringValue(ARTICLE_CONTENT_TYPE)
 36                        )
 37                )
 38        )
 39
 40        if (userTerm) {
 41            // Check if the user is requesting an exact match with quotes
 42            def matcher = userTerm =~ /.*("([^"]+)").*/
 43            if (matcher.matches()) {
 44                // Using must excludes any doc that doesn't match with the input from the user
 45                query.must(q -> q
 46                        .multiMatch(m -> m
 47                                .query(matcher.group(2))
 48                                .fields(ARTICLE_SEARCH_FIELDS)
 49                                .fuzzyTranspositions(false)
 50                                .autoGenerateSynonymsPhraseQuery(false)
 51                        )
 52                )
 53
 54                // Remove the exact match to continue processing the user input
 55                userTerm = StringUtils.remove(userTerm, matcher.group(1))
 56            } else {
 57                // Exclude docs that do not have any optional matches
 58                query.minimumShouldMatch("1")
 59            }
 60
 61            if (userTerm) {
 62                // Using should makes it optional and each additional match will increase the score of the doc
 63                query
 64                // Search for phrase matches including a wildcard at the end and increase the score for this match
 65                        .should(q -> q
 66                                .multiMatch(m -> m
 67                                        .query(userTerm)
 68                                        .fields(ARTICLE_SEARCH_FIELDS)
 69                                        .type(TextQueryType.PhrasePrefix)
 70                                        .boost(1.5f)
 71                                )
 72                        )
 73                // Search for matches on individual terms
 74                        .should(q -> q
 75                                .multiMatch(m -> m
 76                                        .query(userTerm)
 77                                        .fields(ARTICLE_SEARCH_FIELDS)
 78                                )
 79                        )
 80            }
 81        }
 82
 83        SearchRequest request = SearchRequest.of(r -> r
 84                .query(query.build()._toQuery())
 85        )
 86
 87        def result = searchClient.search(request, Map)
 88
 89        if (result) {
 90            return processUserSearchResults(result)
 91        } else {
 92            return []
 93        }
 94    }
 95
 96    private def processUserSearchResults(result) {
 97        def articles = []
 98        def hits = result.hits().hits()
 99
100        if (hits) {
101            hits.each {hit ->
102                def doc = hit.source()
103                def article = [:]
104                article.id = doc.objectId
105                article.objectId = doc.objectId
106                article.path = doc.localId
107                article.title = doc.title_t
108                article.url = urlTransformationService.transform("storeUrlToRenderUrl", doc.localId)
109
110                articles << article
111            }
112        }
113
114        return articles
115    }
116
117}

Search Methods/Groovy Code¶

You might encounter the following error in your project, which indicates your search methods in your groovy code needs to be updated for OpenSearch:

Error message in logs indicating groovy code needs to be updated¶
Caused by: org.craftercms.engine.exception.ScriptException: No signature of method: org.craftercms.engine.search.SiteAwareOpenSearchClient.search() is applicable for
    argument types: (org.opensearch.action.search.SearchRequest) values: [SearchRequest{searchType=QUERY_THEN_FETCH, indices=[],
    indicesOptions=IndicesOptions[ignore_unavailable=false, allow_no_indices=true, expand_wildcards_open=true, expand_wildcards_closed=false, expand_wildcards_hidden=false,
    allow_aliases_to_multiple_indices=true, forbid_closed_indices=true, ignore_aliases=false, ignore_throttled=true], routing='null', preference='null', requestCache=null,
    scroll=null, maxConcurrentShardRequests=0, batchedReduceSize=512, preFilterShardSize=null, allowPartialSearchResults=null, localClusterAlias=null,
    getOrCreateAbsoluteStartMillis=-1, ccsMinimizeRoundtrips=true, source={"from":0,"size":6,"query":{"query_string":{"query":"content-type:\"/page/blogpost\" AND ( (NOT
    (_exists_:unlisted_b)) OR unlisted_b:false) ","fields":[],"type":"best_fields","default_operator":"or","max_determinized_states":10000,"enable_position_increments":true,
    "fuzziness":"AUTO","fuzzy_prefix_length":0,"fuzzy_max_expansions":50,"phrase_slop":0,"escape":false,"auto_generate_synonyms_phrase_query":true,"fuzzy_transpositions":true,
    "boost":1.0}},"sort":[{"publishedDate_dt":{"order":"desc"}}]}, cancelAfterTimeInterval=null, pipeline=null}]
Possible solutions: search(org.opensearch.client.opensearch.core.SearchRequest, java.lang.Class, java.util.Map), each(groovy.lang.Closure), macro(groovy.lang.Closure)
Next
Disaster Recovery
Previous
Upgrading Studio Cluster
Copyright © 2025, Crafter Software Corporation
Made with Sphinx and @pradyunsg's Furo
On this page
  • Upgrading Search
    • Upgrading 3.1.x -> 4.2.0 (from ES 6.x)
    • Upgrading 4.0.x -> 4.2.0 (from ES 7.15)
    • Upgrading 4.1.x -> 4.2.0
    • Manual Updates for Search
      • Updating Search Beans
      • Search Methods/Groovy Code