Only return specific fields in elastic search native query Java api - elasticsearch

I'm building a native query but I only want to return certain fields, all of which are held within a parent field. I think I am looking for the QueryBuilders or NativeSearchQueryBuilder equivalent of the REST API's _source. Here's a code example:
NativeSearchQueryBuilder sb = new NativeSearchQueryBuilder()
.withIndices("myIndex")
.withTypes("myType")
.withQuery(QueryBuilders.queryStringQuery("parent.field2:Foo*"));
.withFields("parent.field1");
I'd expect this to return a list of only parent.field1 that are associated with objects that have parent.field2 like Foo*. But it returns nothing.
Thanks for any help!

After some research, I found the answer is in NativeSearchQueryBuilder. I was just using an older version of spring-data elastic search, so I could not see this method: withSourceFilter. The way to do this is:
NativeSearchQueryBuilder sb = new NativeSearchQueryBuilder()
.withIndices("myIndex")
.withTypes("myType")
.withQuery(QueryBuilders.queryStringQuery("parent.field2:Foo*"));
.withSourceFilter(new FetchSourceFilter(<String array of includes>, null));
FetchSourceFilter takes 2 arguments, a String[] array of includes and one of excludes. In my example, I'd have an array like new String[]{"parent.field1"} passed to FetchSourceFilter, which in turn is passed to withSourceFilter. The search above will then return (once built and ran) a list of parent.field1 with parent.field2 like Foo*.
The version I upgraded to was spring-data-elasticsearch 2.0.2.

Related

Using Spring MongoTemplate to update nested arrays in MongoDB

Can anyone help with a MongoTemplate question?
I have got a record structure which has nested arrays and I want to update a specific entry in a 2nd level array. I can find the appropriate entry easier enough by the Set path needs the indexes of both array entries & the '$' only refers to the leaf item. For example if I had an array of teams which contained an array of player I need to generate an update path like :
val query = Query(Criteria.where( "teams.players.playerId").`is`(playerId))
val update = Update()
with(update) {
set("teams.$.players.$.name", player.name)
This fails as the '$' can only be used once to refer to the index in the players array, I need a way to generate the equivalent '$' for the index in the teams array.
I am thinking that I need to use a separate Aggregate query using the something like this but I can't get it to work.
project().and(ArrayOperators.arrayOf( "markets").indexOf("")).`as`("index")
Any ideas for this Mongo newbie?
For others who is facing similar issue, One option is to use arrayFilters in UpdateOptions. But looks like mongotemplate in spring does not yet support the use of UpdateOptions directly. Hence, what can be done is:
Sample for document which contain object with arrays of arrayObj (which contain another arrays of arrayObj).
Bson filter = eq("arrayObj.arrayObj.id", "12345");
UpdateResult result = mongoTemplate.getDb().getCollection(collectionName)
.updateOne(filter,
new Document("$set", new Document("arrayObj.$[].arrayObj.$[x].someField"), "someValueToUpdate"),
new UpdateOptions().arrayFilters(
Arrays.asList(Filters.eq("x.id, "12345))
));

Elasticsearch QueryBuilder not all fields always there

I'm trying to use a QueryBuilder but I have problems with fields not always being needed.
.setQuery(QueryBuilders.boolQuery()
.must(termQuery("country", countryName))
.must(termQuery("Region", regionName))
.must(termQuery("City", city))
.must(rangeQuery("persons").from(persons))
.get();
In the example above city might not always be needed, but if I leave it empty it searches for an empty city. This is just for city, but I expect 10+ fields later on.
Can I somehow conditionally add things to the builder or is there another smart way?
You can build your query and then pass it to the search request. During building you can conditionally add your statements to the query. It will look like this
BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery()
.must(termQuery("country", countryName))
.must(termQuery("Region", regionName))
.must(rangeQuery("persons").from(persons));
if(city != null && city.trim().equals("")) {
queryBuilder.must(termQuery("City", city));
}
.setQuery(queryBuilder); //add query to your search request

How to do Rescore with Spring Data Elastic search?

I'm using spring boot with the Spring Data Elastic search client.
And I have something like
NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();
QueryBuilder nameQuery = boolQuery().should(matchQuery("fullName", queryText)).boost(10)
.should(matchQuery("fullName", queryText).fuzziness(Fuzziness.ONE)).boost(1.5f)
.should(matchQuery("fullName.autocomplete", queryText)).boost(2f)
.should(matchQuery("fullName.metaphone", queryText)).boost(1.2f)
.should(matchQuery("fullName.synonym", queryText)).boost(2)
.should(matchQuery("fullName.porter", queryText));
searchQueryBuilder.withQuery(nameQuery);
List<MasterIndex> masterIndices = masterIndexRepository.search(searchQueryBuilder.build());
After getting all of the names, I'd like to try with rescoring using some other attributes to reorder the result that might be more relevant. I know there is a rescore query, like this
RescoreBuilder.QueryRescorer rescoreBuilder = RescoreBuilder.queryRescorer(boolQuery().should(hasChildQuery("client",
QueryBuilders.boolQuery()
.should(QueryBuilders.termsQuery("enrollments.programId", programId))
))).setQueryWeight(0.7f).setRescoreQueryWeight(0.3f);
But how to put the rescoreBuilder together with NativeSearchQueryBuilder?
Or if there's any other way to customize score and order the result more intelligently, please let me know.

Spring data elastic search - Query - Full text search

I am trying to use elastic search for full text search and Spring data for integrating elastic search with my application.
For example,
There are 6 fields to be indexed.
1)firstName
2)lastName
3)title
4)location
5)industry
6)email
http://localhost:9200/test/_mapping/
I can see these fields in the mapping.
Now, I would like to make a search against these fields with a search input.
For example, When I search "mike 123", it has to search against all these 6 fields.
In Spring data repository,
The below method works to search only in firstName.
Collection<Object> findByFirstNameLike(String searchInput)
But, I would like to search against all the fields.
I tried,
Collection<Object> findByFirstNameLikeOrLastNameLikeOrTitleLikeOrLocationLikeOrIndustryLikeOrEmailLike(String searchInput,String searchInput1,String searchInput2,String searchInput3,)
Here, even the input string is same, i need to pass the same input as 6 params. Also the method name looks bigger with multiple fields.
Is there anyway to make it simple with #Query or ....
Like,
Collection<Object> findByInput(String inputString)
Also, boosting should be given for one of the field.
For example,
When i search for "mike mat", if there is any match in the firstName, that should be the first one in the result even there are exact match in the other fields.
Thanks
Lets suppose your search term is in the variable query, you can use the method search in ElasticsearchRepository.
repo.search(queryStringQuery(query))
to use queryStringQuery use the following import
import static org.elasticsearch.index.query.QueryBuilders.queryStringQuery;
I found the way to achieve this and posting here. Hope, this would help.
QueryBuilder queryBuilder = boolQuery().should(
queryString("Mike Mat").analyzeWildcard(true)
.field("firstName", 2.0f).field("lastName").field("title")
.field("location").field("industry").field("email"));
Thanks
Not a spring-data elasticsearch expert. But I see two directions you can go. The first would be to use the #Query option. That way you can create your own query. The second would be to use the example in the Filter builder section:
http://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#elasticsearch.misc.filter
Within elasticearch you would want to use the multi_match query:
http://www.elastic.co/guide/en/elasticsearch/reference/1.5/query-dsl-multi-match-query.html
In java such a query would look like this:
QueryBuilder qb = multiMatchQuery(
"kimchy elasticsearch",
"user", "message"
);
Example coming from: http://www.elastic.co/guide/en/elasticsearch/client/java-api/current/query-dsl-queries.html#multimatch
We can write our own custom query as below.
we can specific index, routing value (this is used if alias is used)
SearchQuery searchQuery = new NativeSearchQueryBuilder().withIndices(INDEX)
.withRoute(yourQueryBuilderHelper.getRouteValue())
.withQuery(yourQueryBuilderHelper.buildQuery(yourSearchFilterRequestObject))
.withFilter(yourQueryBuilderHelper.buildFilter(yourSearchFilterRequestObject)).withTypes(TYPE)
.withSort(yourQueryBuilderHelper.buildSortCriteria(yourSearchFilterRequestObject))
.withPageable(yourQueryBuilderHelper.buildPaginationCriteria(yourSearchFilterRequestObject)).build();
FacetedPage<Ticket> searchResults = elasticsearchTemplate.queryForPage(searchQuery, YourDocumentEntity.class);
Its good to use your own queryBuilder helper which can seperate your elasticSearchService from queryBuilder responsibility.
Hope this helps
Thanks
QueryBuilder class is helpful to query from spring Dao to elastic search:
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.QueryBuilder;
QueryBuilder qb = QueryBuilders.boolQuery()
.must(QueryBuilders.termQuery("state", "KA"));
.must(QueryBuilders.termQuery("content", "test4"))
.mustNot(QueryBuilders.termQuery("content", "test2"))
.should(termQuery("content", "test3"));
.should(termQuery("content", "test3"));
Try like this, you can even set importance of the field
QueryBuilder queryBuilder = QueryBuilders.multiMatchQuery(query)
.field("name", 2.0f)
.field("email")
.field("title")
.field("jobDescription", 3.0f)
.type(MultiMatchQueryBuilder.Type.PHRASE_PREFIX);
Another way is using Query String query
Query searchQuery = new StringQuery(
"{\"query\":{\"query_string\":{\"query\":\""+ your-query-here + "\"}}}\"");
SearchHits<Product> products = elasticsearchOperations.search(
searchQuery,
Product.class,
IndexCoordinates.of(PRODUCT_INDEX_NAME));
This will search all the field from your document of specified index

FOSElasticaBundle order query

I am integrating FOSElasticaBundle in my Symfony 2.3 project and I need to sort the results by their price property.
Here is my code:
$finder = $this->container->get('fos_elastica.finder.website.product');
$fieldTerms = new \Elastica\Query\Terms();
$fieldTerms->setTerms('taxon_ids', $taxon_ids_array);
$boolQuery->addMust($fieldTerms);
$resultSet = $finder->find($boolQuery);
How I can do this?
Thanks
Try create a \Elastica\Query object which also contains the sorting information, then send this to the finder:
$finder = $this->container->get('fos_elastica.finder.website.product');
$fieldTerms = new \Elastica\Query\Terms();
$fieldTerms->setTerms('taxon_ids', $taxon_ids_array);
$boolQuery->addMust($fieldTerms);
$finalQuery = new \Elastica\Query($boolQuery);
$finalQuery->setSort(array('price' => array('order' => 'asc')));
$resultSet = $finder->find($finalQuery);
Have a look at the elasticsearch docs on the sort parameter to see how to use it properly.
NOTE: \Elastica\Query is quite different to \Elastica\Query\AbstractQuery, the first encapsulates everything you could send to the _search API endpoint (facets, sorting, explain, etc...) The AbstractQuery represents a base type for each of the individual query types (range, fuzzy, terms, etc...).

Resources