How to search and sort on the same field in HIbernate search - hibernate-search

I am using Hibernate Search 6 configured to an elasticsearch backend.
#Indexed
public class Book extends PanacheEntity{
#FullTextField
public String title;
#GenericField
public Double price;
}
I can filter on the price field for books in a price range, as follows:
Search.session(entityManager)
.search(Book.class)
.predicate(f -> f.bool(b -> {
b.must(f.range().field("price").lessThan(50));
}));
I would like to be able to sort the search results by price as well.
For this I changed the field definition to
#GenericField(sortable = Sortable.YES)
private Double price;
I am doing the sort as follows:
.sort(f -> f.composite(b -> {
b.add(f.field("price");
} ) )
I am getting the error as follows, which looks to have been thrown from Elastic
Can\u0027t load fielddata on [offer.price] because fielddata is unsupported on fields of type [double]. Use doc values instead.
I have seen Can you sort and search on same field with Hibernate/Lucene? but I dont see equivalent annotations in Hibernate search 6

Your code with the sortable = Sortable.YES should work as you expect.
The error returned by Elasticsearch leads me to think your schema (the "mapping" registered to the Elasticsearch cluster) might be obsolete.
You can check that by starting Hibernate Search with the validate lifecycle strategy.
If you get an error, it means your schema is out of date. The easiest solution to update it is to drop your Elasticsearch indexes and let Hibernate Search re-create them.

Related

Read element from nested map by key. mongodb spring data

there is the following structure
#Id
private String beaconMac;
private SortedMap<LocalDate, Map<Integer, HistoryData>> history;
How i can read internal value from 'history' map by key? how to make a right query? or meybe in spring data there is a blank like
NestedObject repo.findNestedObjectByDate(LocalDate date);
Very grateful!
If I understand correctly, you want something like:
db.collection.find({
beaconMac: "C145109D4D5C"
},
{
"history.2020-20-02": 1,
beaconMac: 1
})
The first part is the match, in which you choose what documents you want. The second is the projection, in which you format the fields you want to see.
As You can see on this playground

Hibernate Search add only DocumentId from IndexedEmbedded class

I've an Entity "Invoice" and this one has a many-to-one relationship to Customer-Entity. This Customer-Entity is also used from other Entities for Hibernate Search and so there are many Hibernate Search annotations. For Invoice HS-Index I just want to have the Customer.id in the Invoice index and no other property of Customer.
How is this possible, because in the documentation I've found nothing specific about it.
In recent versions of Hibernate Search, you would simply use #IndexedEmbedded(includePaths = "id").
Hibernate Search 3.4 is very old, though (9 years old), and is missing many features. I'd recommend you upgrade since you're very likely to hit bugs that will never be solved in this version.
If you really have to stick with 3.4, I believe your only solution will be writing a custom bridge:
public class CustomerIdBridge implements StringBridge {
public String objectToString(Object object) {
Customer customer = (Customer) object;
if ( customer == null ) {
return null;
}
Object id = customer.getId();
return id == null ? null : id.toString();
}
}
Then apply the bridge like this:
#ManyToOne(...)
#Field(bridge = #FieldBridge(impl = CustomerIdBridge.class))
private Customer customer;
The resulting field will simply be named "customer" (same name as your property).
See here for more information about bridges in Hibernate Search 3.4.2.

Having conditional multiple filters in Morphia query for Mongo database

Environment : MongoDb 3.2, Morphia 1.1.0
So lets say i am having a collection of Employees and Employee entity has several fields. I need to do something like apply multiple filters (conditional) and return a batch of 10 records per request.
pesudocode as below.
#Entity("Employee")
Employee{
String firstname,
String lastName,
int salary,
int deptCode,
String nationality
}
and in my EmployeeFilterRequesti carry the request parameter to the dao
EmployeeFilterRequest{
int salaryLessThen
int deptCode,
String nationality..
}
Pseudoclass
class EmployeeDao{
public List<Employee> returnList;
public getFilteredResponse(EmployeeFilterRequest request){
DataStore ds = getTheDatastore();
Query<Employee> query = ds.createQuery(Emploee.class).disableValidation();
//conditional request #1
if(request.filterBySalary){
query.filter("salary >", request.salary);
}
//conditional request #2
if(request.filterBydeptCode){
query.filter("deptCode ==", request.deptCode);
}
//conditional request #3
if(request.filterByNationality){
query.filter("nationality ==", request.nationality);
}
returnList = query.batchSize(10).asList();
/******* **THIS IS RETURNING ME ALL THE RECORDS IN THE COLLECTION, EXPECTED ONLY 10** *****/
}
}
SO as explained above in the code.. i want to perform conditional filtering on multiple fields. and even if batchSize is present as 10, i am getting complete records in the collection.
how to resolve this ???
Regards
Punith
Blakes is right. You want to use limit() rather than batchSize(). The batch size only affects how many documents each trip to the server comes back with. This can be useful when pulling over a lot of really large documents but it doesn't affect the total number of documents fetched by the query.
As a side note, you should be careful using asList() as it will create objects out of every document returned by the query and could exhaust your VM's heap. Using fetch() will let you incrementally hydrate documents as you need each one. You might actually need them all as a List and with a size of 10 this is probably fine. It's just something to keep in mind as you work with other queries.

How can I query to find mongo entities whose list of sub-entities contain a field matching a string?

I have a collection of entities that look like this:
public class ClientEntity {
#Id
private String id;
#Indexed(unique = true)
private String clientId;
private String name;
#DBRef
private List<ClientMachineEntity> machines;
...
}
...where ClientMachineEntity looks like:
public class ClientMachineEntity {
#Id
private String id;
#Indexed(unique = true)
private String clientMachineId;
private String hostName;
...
}
I have a working search that finds ClientEntities by matching against "clientId" and "name":
public List<ClientEntity> searchByIdAndName(String id, String name) {
Criteria idCriteria = Criteria.where("clientId").regex(id, "i");
Criteria nameCriteria = Criteria.where("name").regex(name, "i");
Query query = new Query(new Criteria().orOperator(idCriteria, nameCriteria));
...
}
So my question is, how can I expand this search so that it also matches against "clientMachineId" in the list of sub-entities? I tried adding the following criteria:
Criteria machineCriteria = Criteria.where("machines.clientMachineId").regex(id, "i");
...but that doesn't work, presumably because machines is a LIST of entities, not just a single sub-entity.
UPDATE: It seems like what I'm looking for is the .elemMatch() functionality, but when I try that:
Criteria machineCriteria = Criteria.where("machines").elemMatch(Criteria.where("clientMachineId").regex(id, "i"));
...I get the following error:
org.springframework.data.mapping.model.MappingException: No mapping metadata found for class com.mongodb.BasicDBObject
You can't query by fields in subentities linked with DBRef. If ClientMachineEntity would be embedded in ClientMachine - then you could use dot notation or $elemMatch depending on needs.
In your particular example - couldn't field ClientMachineEntity.clientMachineId be saved as _id and used as a primary key? Then you could get the results you need - take a look at: How to query mongodb with DBRef
My suggestion for development with Spring Data MongoDB is - first learn how to (and if it's possible) do it in plain Javascript with MongoDB console, then learn how to do the same with Spring Data MongoDB.

How to map Grails domain object to a specific mongodb table name

I've setup a simple grails app looking at a mongodb.
My domain object looks like this:
class GoogleSearch {
String _id;
String id;
String query;
String site;
Object results;
Date date;
static mapping = {
table 'google_searches'
}
static constraints = {
}
}
However when I run the grails app up, it keeps reading/writing to a table named "googleSearch"
Does anyone know how I can override this default naming? Is it a gorm/mongodb thing?
Cheers
Basics of MongoDB. There is no concept of table. It is always collections. :)
Refer mapping as collection 'google_searches'.
For more details you can refer Grails MongoDB plugin.