How can I make phrase suggester query with Elasticsearch java api? - elasticsearch

I am using 7.10. version of elasticsearch. I created an index and did settings-mappings. Then I sent query to index by using http requests. I got the results I need, but I want to do same thing with Java API. However, I couldn't.
Can you help me to send request and get the result as list in java from scratch ?
And here it is my query that I used for obtain suggestions:
{
"suggest": {
"text": "some title I want to search",
"phrase_suggester": {
"phrase": {
"field": "title.shingle",
"max_errors": 2,
"size": 5,
"confidence": 0.0,
"direct_generator": [{
"field": "title.shingle",
"max_edits": 2
}
]
}
}
}
}
How can I write this query with Elasticsearch Java API. Can you help me figure this out ?

This would be the way to build the request:
client.search(searchRequestBuilder -> searchRequestBuilder
.suggest(suggestBuilder -> suggestBuilder
.text("some title I want to search")
.suggesters("phrase_suggester", fieldSuggesterBuilder -> fieldSuggesterBuilder
.phrase(phraseBuilder -> phraseBuilder.field("title.shingle")
.maxErrors(2d)
.size(5)
.confidence(0.0)
.directGenerator(directGeneratorBuilder -> directGeneratorBuilder
.field("title.shingle")
.maxEdits(2))))),
YourEntity.class);
Btw, the new client was in 7.16, you wrote 7.14?

Finaly I've found my own answers. It was so hard to find the solution due to lack of documents about these kind of specific topics. I'm sharing my solution for those who wondered:
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
PhraseSuggestionBuilder builder = SuggestBuilders.phraseSuggestion("title.shingle")
.addCandidateGenerator(new DirectCandidateGeneratorBuilder("title.shingle")
.suggestMode("always"))
.text(query)
.maxErrors(2f)
.confidence(0f);
SuggestBuilder suggestBuilder = new SuggestBuilder().addSuggestion("suggestion", builder);
searchSourceBuilder.suggest(suggestBuilder);
SearchRequest searchRequest = new SearchRequest();
searchRequest.indices("index_name");
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);

Related

Elasticsearch search Java API doesn't give correct results

I have following code for ES search:
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(
new HttpHost("localhost", 9200, "http")));
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
qb = QueryBuilders.termQuery("title", "Java");
searchSourceBuilder.query(qb);
searchSourceBuilder.from(0);
searchSourceBuilder.size(5);
SearchRequest searchRequest = new SearchRequest("myindex");
searchRequest.types("books");
searchRequest.source(searchSourceBuilder);
SearchResponse sr = client.search(searchRequest);
System.out.println(sr.getHits().totalHits);
It gives me no results, even though there are documents meeting this criteria.
When I run similar term query from Kibana, I get results:
GET /myindex/books/_search
{
"query":
{
"term" : {
"title" : {
"value" : "java"
}
}
}
}
The difference is Java (with uppercase) in your Java code and java (in lowercase) in your Kibana query.
Since you're doing a term query, the case matters. If you used a match query, the case doesn't matter and both would work as you expect.

How can I make a SearchRequest in ES 6.0 from a json string using High level REST Client in Scala

I'm migrating from ES 1.7 to 6.0 and I'm trying to figure out a way to perform a search request passing a plain query to the High Level REST Java client. To keep queries easy to read (and maintain), we want to use a Json string instead of building them with the SearchSourceBuilder. This was possible before but I'm not finding a nice way to do it now.
Example query:
{
"filter": {
"bool": {
"must": [
{
"term": {
"status": "Success"
}
},
{
"term": {
"type": "someType"
}
},
{
"range": {
"endDateTime": {
"lte": "someDateTime"
}
}
}
]
}
}
}
Example code:
val searchRequest = buildSearchRequest(indexName, indexType, query)
val searchResponse = restHighLevelClient.search(searchRequest)
I know it's possible to send the query using the LowLevelClient but it returns a Response and not a SearchResponse. Has anyone faced this issue before? Any workaround or solution?
I'm a little bit late, but I have a close solution for your problem.
Firstly, you need to build your query with something like this:
private QueryBuilder buildQuery(MyObject object) {
BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
QueryBuilder statusTerm = QueryBuilders.termQuery("status", object.getStatus());
QueryBuilder typeTerm = QueryBuilders.termQuery("type", object.getType());
QueryBuilder boolQuery = QueryBuilders.boolQuery()
.must(statusTerm)
.must(typeTerm);
queryBuilder.should(boolQuery);
return queryBuilder;
}
Then, you can perform your search and return SearchResponse:
private SearchResponse search(QueryBuilder query) throws IOException {
SearchRequest request = new SearchRequest(elasticSearchClient.getElasticsearchClientProperties().getIndices());
SearchSourceBuilder searchRequestBuilder = request.source();
searchRequestBuilder.query(query);
//SearchSourcebuilder allows you to set your query into your request
return this.elasticSearchClient.search(request);
}
Finally, can have a method that calls both:
public void processSearch(MyObject object) {
QueryBuilder query = buildQuery(object);
SearchResponse response = search(query);
List<FoundObjects> objects = parseResponse(response);
}
I hope this could help. Good luck!

Post Filter Query in Elasticsearch 2.3.3 using Java

I have built a web app on top of elasticsearch (v2.3.3). To filter the query, I am using post filter of elasticsearch. But I came to know that, if I use post filter then the performance benefit of filtering will be lost since I am not using any aggregation or differential filtering. (Reference: https://www.elastic.co/guide/en/elasticsearch/guide/current/_post_filter.html)
This is how my elasticsearch client looks like:
Client client = TransportClient.builder().build().addTransportAddress(
new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"),
9300));
SearchResponse response = client.prepareSearch("index_name")
.setTypes("index_type")
.setQuery(QueryBuilders.simpleQueryStringQuery(query)
.field("newContent").field("T"))
.setPostFilter(QueryBuilders.termQuery(Collection, true))
.setFetchSource(new String[] { "U", "UE", "UD", "T" }, null)
.setVersion(true).addHighlightedField("newContent").setFrom(0)
.setSize(10).execute().actionGet();
I have also read that filtered query is depreciated in elasticsearch 2.x versions. Is there any other way which will help me to apply a filter before the query is executed? I might be missing something obvious. I would appreciate your help.
You simply need to bring the filter present in post filter inside a bool/filter query. Try to do hits instead:
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery()
.must(QueryBuilders.simpleQueryStringQuery(query)
.field("newContent").field("T"))
.filter(QueryBuilders.termQuery(Collection, true));
SearchResponse response = client.prepareSearch("index_name")
.setTypes("index_type")
.setQuery(boolQuery)
.setFetchSource(new String[] { "U", "UE", "UD", "T" }, null)
.setVersion(true).addHighlightedField("newContent").setFrom(0)
.setSize(10).execute().actionGet();

Obtaining string query (JSON) from SearchQuery object

For debugging purposes, I need to know what query spring-data-elasticsearch is sending to the ElasticSearch cluster. I have tried to call the toString method on the SearchQuery object, and doesn't return what I need.
What I am doing in Java (using spring-data-elasticsearch) is:
private FilterBuilder getFilterBuilder(String id) {
return orFilter(
termFilter("yaddayaddayadda.id", id),
termFilter("blahblahblah.id", id)
);
}
SearchQuery sq = NativeSearchQueryBuilder()
.withQuery(new MatchAllQuery())
.withFilter(fb)
.build();
And I expect to return something like this plain query executed in ES cluster REST API is returning:
{
"query": {
"filtered": {
"filter": {
"or": [
{
"term": {
"yaddayaddayadda.id": "9"
}
},
{
"term": {
"blahblahblah.id": "9"
}
}
]
}
}
}
}
Thanks in advance!
One way to achieve this is to log the queries on the ES/server-side into the slowlog file. Open your elasticsearch.yml config file and towards the bottom uncomment/edit the two lines below:
...
index.search.slowlog.threshold.query.info: 1ms
...
index.search.slowlog.threshold.fetch.info: 1ms
...
The advantage of this solution is that whatever client technology you're using to query your ES server (Spring Data, Ruby, Browser, Javascript, etc), you'll be able to dump and debug your queries in a single location.
SearchQuery Interface has a method getQuery() and getFilter() to get the information you need.
System.out.println(searchQuery.getQuery());
System.out.println(searchQuery.getFilter());
Hope this helps.
When using SearchRequest or SearchSourceBuilder, calling .toString() method on their instance will get you actual JSON query:
SearchRequest searchRequest = new SearchRequest("index");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
// building the query
// ...
searchSourceBuilder.query(query);
searchRequest.source(searchSourceBuilder);
System.out.println(searchSourceBuilder.toString()); // prints json query
System.out.println(searchRequest.toString()); // prints json query + other information

ElasticSearch Facets

I have following elastic search query
SearchResponse response = DbContext.INSTANCE.client()
.prepareSearch(indexList)
.setTypes("docs")
.setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
.setQuery(queryBuilder)
.setFilter(FilterBuilders.andFilter(f1, f2))
.addFacet(FacetBuilders.termsFacet("f").field("frm").size(10))
.setFrom(pageNumber).setSize(size).execute().actionGet();
Facet count return by this query is global, how to get the facet for the search response?
I found the answer: What I done is add filter to the main query
QueryBuilder queryBuilder = QueryBuilders.boolQuery()
.must(QueryBuilders.queryString(criterion.getFullText()).field("text"))
.must(QueryBuilders.termsQuery("from", criterion.getFrom().toArray((new String[0]))))
.must(QueryBuilders.termsQuery("to", criterion.getTo().toArray((new String[0]))))
.must(QueryBuilders.rangeQuery("date").from(dtf.print(criterion.getFromDate())).to(dtf.print(criterion.getToDate())));
SearchResponse response =
DbContext.INSTANCE.client()
.prepareSearch(indexList)
.setTypes("docs")
.setQuery(queryBuilder)
.addFacet(fb)
.addFacet(tf)
.addSort("date", SortOrder.DESC)
.setFrom(pageNumber).setSize(size).execute().actionGet();
This is what i did unless you want "main" search and facet has different search requirement.
global=false should do the trick for you
"facets": {
"volume_by_day": {
"date_histogram": {
"field": "crdate",
"interval": "day"
},
"global": "false"
}
}

Resources