Searching

Requirements for searching are FieldConfiguration definitions for the index, a created index and some indexed documents.

The main components for searching are the Expression classes, which define what you search, and the SearchParameter class, which defines how you search. The executive component for searching is the ElasticsearchService.

If only one index is used, searches can be performed using the SingleIndexElasticsearchService:

SearchResult searchResult = singleIndexElasticsearchService
    .search(expression, searchParameter);

If a custom index is to be searched, the ElasticsearchService must be used:

SearchResult searchResult = elasticsearchService
    .search(indexAlias, expression, searchParameter);

Several Expression-based search samples can be found here.

Search sample

The following example performs a simple fulltext search for a maximum of 1000 hits and returns 100 results from the first result page, sorted by id desc:

Expression expression = new FulltextExpression("test");
SearchParameter searchParameter = SearchParameter.builder()
        .pageIndex(1)
        .pageSize(100)
        .maxResults(1000)
        .maxTrackTotalHits(10000L)
        .aggregations(DefaultAggregation.field("keyword"))
        .sortOptions(SortOption.asc("id")).build();

SearchResult searchResult 
    = singleIndexElasticsearchService.search(expression, searchParameter);

long totalHitCount = searchResult.getTotalHitCount();
int pageCount = searchResult.getPageCount();
List<SearchResultItem> searchResultItems = searchResult.getSearchResultItems();

To get the next (or any other) page of a search result, the previous search must be executed again with the new page index.

A pagination sample can be found here.

Search result

The following example provides an overview of the search result:

SearchResult searchResult
        = singleIndexElasticsearchService.search(expression, searchParameter);

// Count of search result items
int resultCount = searchResult.getResultCount();

// Total number of search hits
// If this value exceeds the configured maximum number of total hits tracked, 
// the total number of hits is marked as not exact.
long totalHitCount = searchResult.getTotalHitCount();

// TRUE if total hit count exact number,
// FALSE if total hit count is greater than the given number.
boolean isExactHitCount = searchResult.isExactHitCount();

// Page count (number of result pages) 
// Depending on the result count and the page size.
int pageCount = searchResult.getPageCount();

// Index of the result page
// Corresponds to pageIndex of SearchParameter.
int pageIndex = searchResult.getPageIndex();

// Fields and values of the corresponding index documents 
// of the requested result page
List<SearchResultItem> searchResultItems = searchResult.getSearchResultItems();
for (SearchResultItem searchResultItem : searchResultItems) {
    String id = searchResultItem.getId();
    Map<String, Object> attributes =  searchResultItem.getAttributes();
}

// IDs of the result items of the requested result page
// If no IDs are used in the index, the values will be -1.
List<String> ids = searchResult.getIds();

// Facets of search result
// Available if corresponding aggregations were passed via `SearchParameter`.
List<ResultFacet> facets = searchResult.getFacets();

Query logging

If you want to have an insight into the JSON query picturesafe-search is sending to Elasticsearch, you can enable the query logging by modifying you logging configuration. All you have to do is setting the log level for elasticsearch-query logger to debug. Since picturesafe-search uses SLF4J for its logging output, all the common Java logging frameworks are supported. In this example, the configuration for Log4j is shown.

Log4j configuration snippet:

<Loggers>
    <Logger name="de.picturesafe.search" level="info"/>
    <Logger name="elasticsearch-query" level="debug"/>
    <Root level="info">
        <AppenderRef ref="File"/>
    </Root>
</Loggers>

Query logging output:

15:03:33.616 [main] [DEBUG] elasticsearch-query - Search request 328f75e2-c1bb-4a28-8d55-ccba0b90f5e6:
QueryDto:{"expression":"FulltextExpression:{"name":"fulltext","comparison":"EQ","value":"Hamburg","matchPhrase":false}","queryRangeDto":"QueryRangeDto:{"start":0,"limit":100,"maxTrackTotalHits":null}","sortOptions":[SortOption:{"fieldName":"id","sortDirection":"DESC","filter":null,"arrayMode":"DEFAULT"}],"aggregations":[],"locale":"de","fieldsToResolve":[],"fieldResolverType":"SOURCE_VALUES"}
{"from":0,"size":100,"query":{"query_string":{"query":"Hamburg","fields":["fulltext^1.0"],"type":"best_fields","default_operator":"and","max_determinized_states":10000,"enable_position_increments":true,"fuzziness":"AUTO","fuzzy_prefix_length":0,"fuzzy_max_expansions":50,"phrase_slop":0,"analyze_wildcard":false,"escape":false,"auto_generate_synonyms_phrase_query":true,"fuzzy_transpositions":true,"boost":1.0}},"sort":[{"id.keyword":{"order":"desc","missing":"_last"}}]}

15:03:33.627 [main] [DEBUG] elasticsearch-query - Search response 328f75e2-c1bb-4a28-8d55-ccba0b90f5e6:
{"took":1,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":{"value":2,"relation":"eq"},"max_score":null,"hits":[{"_index":"test_index-20200625-150332-381","_type":"_doc","_id":"4712","_score":null,"_source":{"name":"name-4712","caption":"Document caption #4712\nThis document was created for testing purposes.\nÄÖÜäöüß","location":"Hamburg","id":"4712","title":"Die Katze jagt Vögel in Hamburg","createDate":"2020-06-25T15:03:33.263+02:00"},"sort":["4712"]},{"_index":"test_index-20200625-150332-381","_type":"_doc","_id":"4711","_score":null,"_source":{"name":"name-4711","caption":"Document caption #4711\nThis document was created for testing purposes.\nÄÖÜäöüß","location":"Hamburg","id":"4711","title":"Der Hund beißt sich in den Schwanz in Hamburg","createDate":"2020-06-25T15:03:33.248+02:00"},"sort":["4711"]}]}},

Note: Each query logging output contains an UUID to correlate the query with its result.

Search request log output:

Line Content
1 “Search request UUID:”
2 Internal picturesafe-search QueryDto containing expression, sort options, aggregations, etc.
3 Query JSON which is sent to Elasticsearch

Search response log output:

Line Content
1 “Search response UUID:”
3 Result JSON which is returned by Elasticsearch