Skip to content

Commit

Permalink
Updates to use the new Elasticsearch Client (#83)
Browse files Browse the repository at this point in the history
  • Loading branch information
jdrossl authored Mar 25, 2022
1 parent 26d0fbf commit 6077a90
Show file tree
Hide file tree
Showing 10 changed files with 109 additions and 54 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
*.iml
.idea
node_modules
2 changes: 1 addition & 1 deletion craftercms-plugin.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ plugin:
version:
major: 2
minor: 0
patch: 14
patch: 15
description: |
A versatile blog blueprint.
website:
Expand Down
143 changes: 98 additions & 45 deletions scripts/classes/org/craftercms/sites/wordify/SearchHelper.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -16,84 +16,112 @@

package org.craftercms.sites.wordify

import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery
import co.elastic.clients.elasticsearch._types.query_dsl.Query
import co.elastic.clients.elasticsearch._types.query_dsl.TextQueryType
import org.apache.commons.lang3.StringUtils
import org.craftercms.engine.service.UrlTransformationService
import org.elasticsearch.action.search.SearchRequest
import org.elasticsearch.index.search.MatchQuery
import org.elasticsearch.search.sort.FieldSortBuilder
import org.elasticsearch.search.sort.SortOrder

import static org.elasticsearch.index.query.QueryBuilders.boolQuery
import static org.elasticsearch.index.query.QueryBuilders.matchQuery
import static org.elasticsearch.index.query.QueryBuilders.multiMatchQuery
import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource
import org.craftercms.search.elasticsearch.client.ElasticsearchClientWrapper

class SearchHelper {

static final String POST_CONTENT_TYPE = "/component/post"
static final Map<String, Float> POST_SEARCH_FIELDS = [
'headline_t': 1.5f,
'content_o.item.component.content_html': 1.0f
static final List<String> POST_SEARCH_FIELDS = [
'headline_t^1.5',
'content_o.item.component.content_html^1.0'
]
static final int DEFAULT_START = 0
static final int DEFAULT_ROWS = 10

def elasticsearch
ElasticsearchClientWrapper elasticsearchClient
UrlTransformationService urlTransformationService

SearchHelper(elasticsearch, UrlTransformationService urlTransformationService) {
this.elasticsearch = elasticsearch
SearchHelper(ElasticsearchClientWrapper elasticsearchClient, UrlTransformationService urlTransformationService) {
this.elasticsearchClient = elasticsearchClient
this.urlTransformationService = urlTransformationService
}

def search(userTerm, start = DEFAULT_START, rows = DEFAULT_ROWS) {
def query = boolQuery()
def query = new BoolQuery.Builder()

// Filter by content-type
query.filter(matchQuery("content-type", POST_CONTENT_TYPE))
query.filter(q -> q
.match(m -> m
.field("content-type")
.query(v -> v
.stringValue(POST_CONTENT_TYPE)
)
)
)

if (userTerm) {
// Check if the user is requesting an exact match with quotes
def matcher = userTerm =~ /.*("([^"]+)").*/
if (matcher.matches()) {
// Using must excludes any doc that doesn't match with the input from the user
query.must(multiMatchQuery(matcher.group(2))
.fields(POST_SEARCH_FIELDS)
.fuzzyTranspositions(false)
.autoGenerateSynonymsPhraseQuery(false))
query.must(q -> q
.multiMatch(m -> m
.query(matcher.group(2))
.fields(POST_SEARCH_FIELDS)
.fuzzyTranspositions(false)
.autoGenerateSynonymsPhraseQuery(false)
)
)

// Remove the exact match to continue processing the user input
userTerm = StringUtils.remove(userTerm, matcher.group(1))
} else {
// Exclude docs that do not have any optional matches
query.minimumShouldMatch(1)
query.minimumShouldMatch('1')
}

if (userTerm) {
// Using should makes it optional and each additional match will increase the score of the doc
query
// Search for phrase matches including a wildcard at the end and increase the score for this match
.should(multiMatchQuery(userTerm)
.fields(POST_SEARCH_FIELDS)
.type(MatchQuery.Type.PHRASE_PREFIX)
.boost(1.5f))
.should(q -> q
.multiMatch(m -> m
.query(userTerm)
.fields(POST_SEARCH_FIELDS)
.type(TextQueryType.PhrasePrefix)
.boost(1.5f)
)
)
// Search for matches on individual terms
.should(multiMatchQuery(userTerm).fields(POST_SEARCH_FIELDS))
.should(q -> q
.multiMatch(m -> m
.query(userTerm)
.fields(POST_SEARCH_FIELDS)
)
)
// Search for matches on additional _s fields (not supported by multi_match)
.should(matchQuery("pageDescription_s", userTerm))
.should(matchQuery("categories_o.item.value_smv", userTerm))
.should(q -> q
.match(m -> m
.field('pageDescription_s')
.query(v -> v
.stringValue(userTerm)
)
)
)
.should(q -> q
.match(m -> m
.field('categories_o.item.value_smv')
.query(v -> v
.stringValue(userTerm)
)
)
)
}
}

def builder = searchSource()
.query(query)
def searchResult = elasticsearchClient.search(r -> r
.query(query.build()._toQuery())
.from(start)
.size(rows)

def searchResult = elasticsearch.search(new SearchRequest().source(builder))
, Map.class)

def result = [:]
result.total = searchResult.hits.getTotalHits()
result.total = searchResult.hits().total().value()

if (searchResult) {
result.hits = processPostListingResults(searchResult)
Expand All @@ -105,9 +133,16 @@ class SearchHelper {
}

def searchPosts(categories = null, start = DEFAULT_START, rows = DEFAULT_ROWS, exclude = null, tags = null) {
def query = boolQuery()
def query = new BoolQuery.Builder()

query.filter(matchQuery("content-type", POST_CONTENT_TYPE))
query.filter(q -> q
.match(m -> m
.field('content-type')
.query(v -> v
.stringValue(POST_CONTENT_TYPE)
)
)
)

if (categories) {
query.filter(getFieldQueryWithMultipleValues("categories_o.item.key", categories))
Expand All @@ -116,19 +151,30 @@ class SearchHelper {
query.filter(getFieldQueryWithMultipleValues("tags_o.item.key", tags))
}
if (exclude) {
query.mustNot(matchQuery("objectId", exclude))
query.mustNot(q -> q
.match(m -> m
.field('objectId')
.query(v -> v
.stringValue(exclude)
)
)
)
}

def builder = searchSource()
.query(query)
def searchResult = elasticsearchClient.search(r -> r
.query(query.build()._toQuery())
.from(start)
.size(rows)
.sort(new FieldSortBuilder("lastModifiedDate_dt").order(SortOrder.DESC))

def searchResult = elasticsearch.search(new SearchRequest().source(builder))
.sort(s -> s
.field(f -> f
.field('lastModifiedDate_dt')
.order(co.elastic.clients.elasticsearch._types.SortOrder.Desc)
)
)
, Map.class)

def result = [:]
result.total = searchResult.hits.getTotalHits()
result.total = searchResult.hits().total().value()

if (searchResult) {
result.hits = processPostListingResults(searchResult)
Expand Down Expand Up @@ -162,7 +208,7 @@ class SearchHelper {

private def processPostListingResults(result) {
def posts = []
def documents = result.hits.hits*.getSourceAsMap()
def documents = result.hits().hits()*.source()

if (documents) {
documents.each {doc ->
Expand Down Expand Up @@ -196,7 +242,14 @@ class SearchHelper {
values = values as String
}

return matchQuery(field, values)
return Query.of(q -> q
.match(m -> m
.field(field)
.query(v -> v
.stringValue(values)
)
)
)
}

}
2 changes: 1 addition & 1 deletion scripts/pages/about.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import org.craftercms.sites.wordify.SearchHelper

def searchHelper = new SearchHelper(elasticsearch, urlTransformationService)
def searchHelper = new SearchHelper(elasticsearchClient, urlTransformationService)
def page = (params.page && Integer.parseInt(params.page) > 0) ? (Integer.parseInt(params.page) - 1) : 0
def postsPerPage = 8

Expand Down
2 changes: 1 addition & 1 deletion scripts/pages/category.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import org.craftercms.sites.wordify.SearchHelper

def requestURI = request.requestURI
def taxonomyHelper = new TaxonomyHelper(siteItemService)
def searchHelper = new SearchHelper(elasticsearch, urlTransformationService)
def searchHelper = new SearchHelper(elasticsearchClient, urlTransformationService)
def itemId = params.id
def taxonomy

Expand Down
2 changes: 1 addition & 1 deletion scripts/pages/contact.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@

import org.craftercms.sites.wordify.SearchHelper

def searchHelper = new SearchHelper(elasticsearch, urlTransformationService)
def searchHelper = new SearchHelper(elasticsearchClient, urlTransformationService)
templateModel.postsInfo = searchHelper.getPostsInfo()
2 changes: 1 addition & 1 deletion scripts/pages/entry.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import org.craftercms.sites.wordify.SearchHelper

def searchHelper = new SearchHelper(elasticsearch, urlTransformationService)
def searchHelper = new SearchHelper(elasticsearchClient, urlTransformationService)
def page = (params.page && Integer.parseInt(params.page) > 0) ? (Integer.parseInt(params.page) - 1) : 0
def postsPerPage = 8

Expand Down
2 changes: 1 addition & 1 deletion scripts/pages/post.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import org.craftercms.sites.wordify.SearchHelper

def searchHelper = new SearchHelper(elasticsearch, urlTransformationService)
def searchHelper = new SearchHelper(elasticsearchClient, urlTransformationService)
def page = (params.page && Integer.parseInt(params.page) > 0) ? (Integer.parseInt(params.page) - 1) : 0
def postsPerPage = 8

Expand Down
2 changes: 1 addition & 1 deletion scripts/pages/postcontainer.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import org.craftercms.sites.wordify.SearchHelper

def searchHelper = new SearchHelper(elasticsearch, urlTransformationService)
def searchHelper = new SearchHelper(elasticsearchClient, urlTransformationService)
def page = (params.page && Integer.parseInt(params.page) > 0) ? (Integer.parseInt(params.page) - 1) : 0
def postsPerPage = 8

Expand Down
4 changes: 2 additions & 2 deletions scripts/pages/search.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import org.craftercms.sites.wordify.SearchHelper

def searchHelper = new SearchHelper(elasticsearch, urlTransformationService)
def searchHelper = new SearchHelper(elasticsearchClient, urlTransformationService)

def userTerm = params.q ? params.q : ''
def page = (params.page && Integer.parseInt(params.page) > 0) ? (Integer.parseInt(params.page) - 1) : 0
Expand All @@ -26,7 +26,7 @@ def results = searchHelper.search(userTerm, page * postsPerPage, postsPerPage)

def pagination = [:]

pagination.totalResults = results.total instanceof String ? results.total : results.total.value.toDouble()
pagination.totalResults = results.total
pagination.pages = Math.ceil(pagination.totalResults/postsPerPage)
pagination.currentPage = page + 1

Expand Down

0 comments on commit 6077a90

Please sign in to comment.