1
votes

I would like to build an ecommerce search engine for different kind of products with elasticsearch 2.4.2 and a spring boot 1.5.4 microservice which provides a search api. I created a working mapping with different analyzers and got it also working with a native elasticsearch json query using sense. You can see the working query (native) at the bottom of this question. This query returns a list of search results with some aggregations for the facet navigation. So it's working fine. Using spring boot with spring-data-elasticsearch to execute this query results in some exception while serializing the AggregatedPage result to json. You can find the exception in the following code-quotes. Does somebody know what's wrong here? Is there a mistake building the query in spring boot or is it a framework bug? Does somebody know a workaround or solution for that?

The controller method:

@RequestMapping(value = "/products", method = RequestMethod.GET)
    @ResponseStatus(HttpStatus.OK)
    public AggregatedPage<PageDocument> searchProducts(@RequestParam("q") String searchPhrase, Pageable pageable) {
        return searchService.search(searchPhrase, pageable);
    }

Request response (exception):

{
  "timestamp": 1499961386848,
  "status": 500,
  "error": "Internal Server Error",
  "exception": "org.springframework.http.converter.HttpMessageNotWritableException",
  "message": "Could not write JSON: show_terms_doc_count_error is false; nested exception is com.fasterxml.jackson.databind.JsonMappingException: show_terms_doc_count_error is false (through reference chain: org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl[\"aggregations\"]->org.elasticsearch.search.aggregations.InternalAggregations[\"asMap\"]->com.google.common.collect.Maps$TransformedEntriesMap[\"stringFacetList\"]->org.elasticsearch.search.aggregations.bucket.nested.InternalNested[\"aggregations\"]->org.elasticsearch.search.aggregations.InternalAggregations[\"asMap\"]->com.google.common.collect.Maps$TransformedEntriesMap[\"stringFacetNames\"]->org.elasticsearch.search.aggregations.bucket.terms.StringTerms[\"buckets\"]->java.util.ArrayList[0]->org.elasticsearch.search.aggregations.bucket.terms.StringTerms$Bucket[\"docCountError\"])",
  "path": "/search/products/"
}

The searchService search method:

public AggregatedPage<PageDocument> search(String searchPhrase, Pageable pageable) {

        NestedBuilder stringAggregationBuilder = AggregationBuilders.nested("stringFacetList")
                .path("searchData.stringFacet")
                .subAggregation(
                        terms("stringFacetNames")
                                .field("searchData.stringFacet.facetName")
                                .subAggregation(
                                        terms("attributeValue")
                                )
                                .subAggregation(
                                        terms("stringFacetValues")
                                                .field("searchData.stringFacet.facetValue")
                                ));

        NestedQueryBuilder searchQuery = nestedQuery("searchData", multiMatchQuery(searchPhrase)
                .field("searchData.fullText", 2)
                .field("searchData.fullTextBoosted", 7)
                .fuzziness(Fuzziness.TWO)
                .analyzer("full_text_search_analyzer")
                .type(Type.MOST_FIELDS));

        SearchQuery nativeSearchQueryBuilder = new NativeSearchQueryBuilder()
                .withPageable(pageable)
                .withQuery(searchQuery)
                .addAggregation(stringAggregationBuilder)
                .build();

        return pageDocumentRepository.search(nativeSearchQueryBuilder);
    }

The working ES-Query (native):

POST /page-documents/page-document/_search
{
   "query": {
      "nested": {
         "query": {
            "multi_match": {
               "query": "Samsung",
               "fields": [
                  "searchData.fullText^2.0",
                  "searchData.fullTextBoosted^7.0"
               ],
               "type": "most_fields",
               "analyzer": "full_text_search_analyzer",
               "fuzziness": "2"
            }
         },
         "path": "searchData"
      }
   },
   "aggregations": {
      "agg_string_facet": {
         "nested": {
            "path": "searchData.stringFacet"
         },
         "aggregations": {
            "facet_name": {
               "terms": {
                  "field": "searchData.stringFacet.facetName"
               },
               "aggregations": {
                  "facet_value": {
                     "terms": {
                        "field": "searchData.stringFacet.facetValue"
                     }
                  }
               }
            }
         }
      }
   }
}

How a native search result using the query above looks like (executed with sense):

 {
   "took": 20,
   "timed_out": false,
   "_shards": {
      "total": 5,
      "successful": 5,
      "failed": 0
   },
   "hits": {
      "total": 33,
      "max_score": 3.7071486,
      "hits": [
         {
            "_index": "page-documents",
            "_type": "page-document",
            "_id": "77891",
            "_score": 3.7071486,
            "_source": {
               "id": "77891",
               "lastUpdated": "2017-07-13T13:08:56.231+0000",
               "documentType": "PRODUCT",
               "searchResultData": {
                  "id": "77891",
                  "name": "Samsung ProXpress M3825DW Drucker",
                  "ean": "8806085488533",
                  "url": null,
                  "manufacturerName": "Samsung",
                  "description": "Samsung ProXpress M3825DW - Drucker - monochrom - Duplex - Laser - A4/Legal - 1200 x 1200 dpi - bis zu 38 Seiten/Min. - Kapazität: 300 Blätter - USB 2.0, LAN, Wi-Fi(n)"
               },
               "searchData": {
                  "fullText": "8806085488533 77891 Samsung ProXpress M3825DW Drucker Samsung",
                  "fullTextBoosted": "Samsung ProXpress M3825DW Drucker",
                  "stringFacet": [
                     {
                        "facetName": "manufacturer",
                        "facetValue": "Samsung"
                     }
                  ],
                  "numberFacet": null
               },
               "completionTerms": null,
               "suggestionTerms": null,
               "scores": {
                  "amazonSalesRank": 0.27778,
                  "contentQuality": 0.15,
                  "isDeal": 0
               },
               "stringSort": {
                  "name": "Samsung ProXpress M3825DW Drucker"
               },
               "numberSort": {
                  "id": 77891
               }
            }
         }
      ]
   },
   "aggregations": {
      "agg_string_facet": {
         "doc_count": 57,
         "facet_name": {
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 0,
            "buckets": [
               {
                  "key": "manufacturer",
                  "doc_count": 28,
                  "facet_value": {
                     "doc_count_error_upper_bound": 0,
                     "sum_other_doc_count": 0,
                     "buckets": [
                        {
                           "key": "Samsung",
                           "doc_count": 15
                        }
                     ]
                  }
               },
               {
                  "key": "color",
                  "doc_count": 19,
                  "facet_value": {
                     "doc_count_error_upper_bound": 0,
                     "sum_other_doc_count": 0,
                     "buckets": [
                        {
                           "key": "Schwarz",
                           "doc_count": 12
                        }
                     ]
                  }
               },
               {
                  "key": "productType",
                  "doc_count": 10,
                  "facet_value": {
                     "doc_count_error_upper_bound": 0,
                     "sum_other_doc_count": 0,
                     "buckets": [
                        {
                           "key": "LCD-Flachdisplay mit LED-Hintergrundbeleuchtung",
                           "doc_count": 2
                        }
                     ]
                  }
               }
            ]
         }
      }
   }
}
1
How did you form the above query in java. if you have any reference or guide please post in commentsarvin_v_s

1 Answers

0
votes

You have to set the show_term_doc_count_error setting to true. This will show an error value for each term returned by the aggregation. See Per bucket document count error.

The org.elasticsearch.search.aggregations.bucket.terms.TermBuilder you are using provides the method showTermDocCountError(boolean showTermDocCountError) that can be used to set the show_term_doc_count_error to true.