Install Solr-9.1.0

Download and extract binaries

curl -L -o solr-9.1.0.tgz https://www.apache.org/dyn/closer.lua/solr/solr/9.1.0/solr-9.1.0.tgz?action=download
tar xvfz solr-9.1.0.tgz

Launch and create taack core

cd solr-9.1.0
bin/solr start
bin/solr create_core -c taack
bin/solr config -c taack -p 8983 -action set-user-property -property update.autoCreateFields -value false
Warning
On a production server, port 8983 should not be reachable from outside.

Copy the file mapping-ISOLatin1Accent.txt in solr configuration dir

The file mapping-ISOLatin1Accent.txt is located in the intranet folder:

cp intranet/server/taack/taack_core_config/conf/mapping-ISOLatin1Accent.txt solr-9.1.0/server/solr/taack/conf/mapping-ISOLatin1Accent.txt

The rest of the configuration should be done at runtime. Only this file is mandatory.

Code adding domain class objects to solr index

Indexing a domain

In the intranet project, look at app/crew/grails-app/services/crew/CrewSearchService.groovy

@PostConstruct
private void init() {
    taackSearchService.registerSolrSpecifier(
        this,
        new SolrSpecifier(User,
            CrewController.&showUserFromSearch as MethodClosure,    (1)
            this.&labeling as MethodClosure, { User u ->            (2)
        u ?= new User()
        indexField "User Name (without Accents)",
            SolrFieldType.TXT_NO_ACCENT, u.username_
        indexField "User Name", SolrFieldType.TXT_GENERAL, u.username_
        indexField "First Name", SolrFieldType.TXT_NO_ACCENT, u.firstName_
        indexField "Last Name", SolrFieldType.TXT_NO_ACCENT, u.lastName_
        indexField "Subsidiary", SolrFieldType.POINT_STRING,
            "mainSubsidiary", true, u.subsidiary?.toString()
        indexField "Business Unit", SolrFieldType.POINT_STRING,
            "businessUnit", true, u.businessUnit?.toString()
        indexField "Date Created", SolrFieldType.DATE, 0.5f, true,  (3)
            u.dateCreated_
        indexField "User Created", SolrFieldType.POINT_STRING,      (3)
            "userCreated",  // Faceting String
            0.5f,           // Boost factor
            true, u.userCreated?.username
    }))
}

You have different choices to process text:

  • POINT_STRING will not modify the string when indexing

  • TXT_NO_ACCENT will remove accents

  • …​

You can index the same field more than once.

Labeling the object found

String labeling(Long id) {
    def u = User.read(id)
    "User: ${u.firstName} ${u.lastName} ($id)"
}

How to display the object

Here CrewController.&showUserFromSearch is used when clicking on the object found:

def showUserFromSearch() {
    User u = User.read(params.long('id'))
    taackUiSimpleService.show(new UiBlockSpecifier().ui {
        ajaxBlock 'showUserFromSearch', {
            show u.username, crewUiService.buildUserShow(u), BlockSpec.Width.MAX
        }
    }, buildMenu())
}
private UiMenuSpecifier buildMenu(String q = null) {
    UiMenuSpecifier m = new UiMenuSpecifier()
    m.ui {
        menu 'Users', CrewController.&index as MC
        menu 'Roles', CrewController.&listRoles as MC
        menu 'Alerts', CrewController.&listAlerts as MC
        menu 'Hierarchy', CrewController.&hierarchy as MC
        menuIcon 'Config MySelf', ActionIcon.CONFIG_USER,
            this.&editUser as MC,
            [id: springSecurityService.currentUserId], true
        menuSearch this.&search as MethodClosure, q         (1)
    }
    m
}
  1. Add menuSearch entry

Search action

def search(String q) {
    taackUiSimpleService.show(crewSearchService.buildSearchBlock(q), buildMenu(q))
}
UiBlockSpecifier buildSearchBlock(String q) {
    taackSearchService.search(q, CrewController.&search as MethodClosure, User) (1)
}
  1. the last parameter is a list of classes we want to target into this search block

We can have more than 1 search result block into a page.