How to search float fields as text in elastic using QueryBuilder - spring-boot

I ve document named plan that correspond plan entity
#Entity
#Table(name = "plan")
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
#org.springframework.data.elasticsearch.annotations.Document(indexName = "plan")
public class Plan extends AbstractAuditingEntity implements Serializable {
#Id
#GeneratedValue
#Column(name = "id")
#Field(type = FieldType.Text , fielddata = true)
private UUID id;
#NotNull
#Column(name = "name", nullable = false, unique = true)
private String name;
#Column(name = "description")
private String description;
#Column(name = "current_price")
#Field(type = FieldType.Text , fielddata = true )
private Float currentPrice;
}
Here my method search implementation
public Page<Plan> search(String query, Pageable pageable) {
NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(queryStringQuery("*"+query+"*").defaultOperator(Operator.AND));
nativeSearchQuery.setPageable(pageable);
List<Plan> hits = elasticsearchTemplate
.search(nativeSearchQuery, Plan.class)
.map(SearchHit::getContent)
.stream()
.collect(Collectors.toList());
return new PageImpl<>(hits, pageable, hits.size());
}
Name and Description are searchable but float field isn't .
Marking as FieldType.Float doesn't give expected result .

Related

Searching multiple fields with multiple queries in Spring Elasticsearch

I am using Spring Elasticsearch. This is my java class :
#Entity
#Document(indexName = "shopindex")
public class Shop implements Serializable {
private #Id #GeneratedValue(strategy = GenerationType.IDENTITY) Long id;
private String imagePath;
#Field(type = FieldType.Text, name = "name")
private String name;
#Field(type = FieldType.Text, name = "description")
private String description;
#Field(type = FieldType.Text, name = "address")
private String address;
#Field(type = FieldType.Text, name = "locality")
private String locality;
#Field(type = FieldType.Keyword, name = "city")
private String city;
#Field(type = FieldType.Keyword, name = "state")
private String state;
private String timing;
#Field(type = FieldType.Nested, includeInParent = true)
private ArrayList<Listing> listings;
Shop () {}
}
I want to have two query strings, location and query. I want query to search through fields name, description, and listing and location to search through fields address, location, city, and state. I am using this query for search but I am getting exception :
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(boolQuery.must(QueryBuilders.multiMatchQuery(location, "address", "locality", "city", "state"))
.must(boolQuery.should(QueryBuilders.multiMatchQuery(query, "name", "description"))
.should(QueryBuilders
.nestedQuery("listings",
QueryBuilders.multiMatchQuery(query, "listings.name", "listings.description"),ScoreMode.Avg))))
.build();
Iterable<Shop> itr = searchRepository.search(searchQuery);

How to set join for predicate

I have a entity for product:
package com.javaschool.entity;
import lombok.*;
import javax.persistence.*;
import java.util.Set;
#EqualsAndHashCode(of = {"id"})
#ToString(of = { "id", "quantity", "price", "model"})
#Entity
#Table(name = "products")
#Data
#NoArgsConstructor
#AllArgsConstructor
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name = "quantity")
private int quantity;
#Column(name = "price")
private int price;
#Column(name = "model")
private String model;
#Column(name = "is_active")
private boolean active;
#Column(name = "picture_url")
private String url;
#ManyToOne(fetch = FetchType.EAGER, optional = false)
#JoinColumn(name = "category_id")
private Category category;
#ManyToOne(fetch = FetchType.EAGER, optional = false)
#JoinColumn(name = "brand_id")
private Brand brand;
#ManyToOne(fetch = FetchType.EAGER, optional = false)
#JoinColumn(name = "season_id")
private Season season;
#ManyToOne(fetch = FetchType.EAGER, optional = false)
#JoinColumn(name = "color_id")
private Color color;
#ManyToOne(fetch = FetchType.EAGER, optional = false)
#JoinColumn(name = "material_id")
private Material material;
#ManyToOne(fetch = FetchType.EAGER, optional = false)
#JoinColumn(name = "size_id")
private Size size;
#ManyToMany(mappedBy = "productSet", fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
private Set<Order> orderSet;
}
I want to filter by category, season, color, brand and other related parameters
At the moment my filtering function looks like this. It works for parameters such as model, price, quantity. That is, for those that are data in this table and not from others. How can I filter by parameters that are taken from other tables?
#Override
public List<Product> findByParam(List<SearchCriteria> params) {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Product> criteriaQuery = criteriaBuilder.createQuery(Product.class);
Root<Product> root = criteriaQuery.from(Product.class);
Predicate predicate = criteriaBuilder.conjunction();
ProductSearchQueryCriteriaConsumer productConsumer = new ProductSearchQueryCriteriaConsumer(predicate, criteriaBuilder, root);
params.stream().forEach(productConsumer);
predicate = productConsumer.getPredicate();
criteriaQuery.where(criteriaBuilder.equal(root.get(Product_.active), true),
predicate);
List<Product> result = entityManager.createQuery(criteriaQuery).getResultList();
return result;
}
I thought that you can make such a call and everything will work. But I was wrong.
List<SearchCriteria> params = new ArrayList<SearchCriteria>();
params.add(new SearchCriteria("season_id", ":", "3"));
List<ProductDto> productDtoList = productService.getProductsByParam(params);
My SearchCriteria
#Data
#AllArgsConstructor
#NoArgsConstructor
public class SearchCriteria {
private String key;
private String operation;
private Object value;
}
Need to make this:
List<SearchCriteria> params = new ArrayList<SearchCriteria>();
params.add(new SearchCriteria("category", ":", categoryRepository.findById(1)));
That is, in the searchcriteria for the value object, pass an object of this class to filter by

Spring Data Jpa One To One mapping with where clause

I have two tables and I need OneToOne mapping with where clause.
select * from person_details inner join address_details
on address_details.pid=person_details.pid AND person_details.exist_flag = 'Y' AND address_details.address_exist_flag = 'Y'
Table 1
public class PersonDetails {
#Id
private String pid;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#Column(name = "exist_flag")
private String existFlag;
#OneToOne(mappedBy = "personDetails", cascade = CascadeType.ALL)
#Where(clause = "addressExistFlag = 'Y'")
private AddressDetails addressDetails;
}
Table 2
#Data
#NoArgsConstructor
#Entity
#Table(name = "address_details")
public class AddressDetails {
#Id
private String pid;
private String street;
#Column(name = "address_exist_flag")
private String addressExistFlag;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "pid", insertable = false, updatable = false)
private PersonDetails personDetails;
}
I need data to be fetched if both addressExistFlag = 'Y' and existFlag = 'Y'.
With current scenario If I am trying to fetch data via spring batch read repository as below, only existFlag = 'Y' is considered. Is it because of incorrect mapping or the way I have used in spring batch
ReadRepository looks like below
public interface PersonDetailsRepository extends JpaRepository<PersonDetails, String> {
Page<PersonDetails> findByExistFlag(String existFlag, Pageable pageable);
}
Spring batch read repository looks like below
#Bean
RepositoryItemReader<PersonDetails> personDetailsItemReader() {
Map<String, Sort.Direction> sort = new HashMap<>();
sort.put("ExistFlag", Sort.Direction.ASC);
return new RepositoryItemReaderBuilder<PersonDetails>()
.repository(personDetailsRepository)
.methodName("findByExistFlag")
.arguments("Y")
.sorts(sort)
.name("personDetailsItemReader")
.build();
}
You are only querying for existsFlag.
You have to add the other Flag too:
public interface PersonDetailsRepository extends JpaRepository<PersonDetails, String> {
Page<PersonDetails> findByExistFlagAndAddressDetailsAddressExistFlag(
String existFlag, String addressExistFlag, Pageable pageable);
}
#Bean
RepositoryItemReader<PersonDetails> personDetailsItemReader() {
Map<String, Sort.Direction> sort = new HashMap<>();
sort.put("ExistFlag", Sort.Direction.ASC);
return new RepositoryItemReaderBuilder<PersonDetails>()
.repository(personDetailsRepository)
.methodName("findByExistFlagAndAddressDetailsAddressExistFlag")
.arguments("Y", "Y")
.sorts(sort)
.name("personDetailsItemReader")
.build();
}

Error while indexing in Hibernate Search - Could not get property value

I am using Hibernate Search with Spring Boot to create a searchable rest api. Trying to POST an instance of "Training", I receive the following stack traces. None of the two are very insightful to me which is why I am reaching out for help.
Stack trace:
https://pastebin.com/pmurg1N3
It appears to me that it is trying to index a null entity!? How can that happen? Any ideas?
The entity:
#Entity #Getter #Setter #NoArgsConstructor
#ToString(onlyExplicitlyIncluded = true)
#Audited #Indexed(index = "Training")
#AnalyzerDef(name = "ngram",
tokenizer = #TokenizerDef(factory = StandardTokenizerFactory.class ),
filters = {
#TokenFilterDef(factory = StandardFilterFactory.class),
#TokenFilterDef(factory = LowerCaseFilterFactory.class),
#TokenFilterDef(factory = StopFilterFactory.class),
#TokenFilterDef(factory = NGramFilterFactory.class,
params = {
#Parameter(name = "minGramSize", value = "2"),
}
)
}
)
#Analyzer(definition = "ngram")
public class Training implements BaseEntity<Long>, OwnedEntity {
#Id
#GeneratedValue
#ToString.Include
private Long id;
#NotNull
#RestResourceMapper(context = RestResourceContext.IDENTITY, path = "/companies/{id}")
#JsonProperty(access = Access.WRITE_ONLY)
#JsonDeserialize(using = RestResourceURLSerializer.class)
private Long owner;
#NotNull
#Field(index = Index.YES, analyze = Analyze.YES, store = Store.YES)
private String name;
#Column(length = 10000)
private String goals;
#Column(length = 10000)
private String description;
#Enumerated(EnumType.STRING)
#Field(index = Index.YES, store = Store.YES, analyze = Analyze.NO, bridge=#FieldBridge(impl=EnumBridge.class))
private Audience audience;
#Enumerated(EnumType.STRING)
#Field(index = Index.YES, store = Store.YES, analyze = Analyze.NO, bridge=#FieldBridge(impl=EnumBridge.class))
private Level level;
#ManyToMany
#Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
#NotNull #Size(min = 1)
#IndexedEmbedded
private Set<ProductVersion> versions;
#NotNull
private Boolean enabled = false;
#NotNull
#Min(1)
#IndexedEmbedded
#Field(index = Index.YES, store = Store.YES, analyze = Analyze.NO)
#NumericField
private Integer maxStudents;
#NotNull
#ManyToOne(fetch = FetchType.LAZY)
private Agenda agenda;
#NotNull
#Min(1)
#Field(index = Index.YES, store = Store.YES, analyze = Analyze.NO)
#NumericField
private Integer durationDays;
#IndexedEmbedded
#Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
#ManyToMany(cascade = CascadeType.PERSIST)
private Set<Tag> tags = new HashSet<>();
I'd say either your versions collection or your tags collection contains null objects, which is generally not something we expect in a Hibernate ORM association, and apparently not something Hibernate Search expects either.
Can you check that in debug mode?

Spring-Data-Jpa OneToMany query duplicate ids in the info log?

I don't understand why the ids are duplicated (id_msg, id_pers_acct), that's what's in my Springboot log :
select personneco0_.id_pers_acct as id_pers_1_2_0_,
…
from test.person_account personacc0_ where personacc0_.id_pers_acct=?
select messages0_.id_pers_acct as id_pers_5_1_0_,
messages0_.id_msg as id_msg1_1_0_,
messages0_.id_msg as id_msg1_1_1_,
messages0_.content as content2_1_1_,
messages0_.date as date3_1_1_,
messages0_.id_pers_acct_person_account as id_pers_4_1_1_,
messages0_.id_pers_acct as id_pers_5_1_1_
from test.message messages0_ where messages0_.id_pers_acct=?
In my entity PersonAccount i have this code :
#OneToMany(mappedBy = "sender", fetch = FetchType.LAZY)
public Set<Message> messages = new HashSet <Message>();
In my entity Message i have this code :
#Entity
#Table(name = "MESSAGE", catalog = "TEST")
public class Message implements Serializable{
/**
*
*/
private static final long serialVersionUID = -602563072975023074L;
#Id
#GeneratedValue
#Column(name = "ID_MSG")
Long idMsg;
#Column(name = "CONTENT")
String content;
#Column(name = "DATE")
Date date;
#Column(name = "ID_PERS_ACCT", nullable = false)
Long sender;
#Column(name = "ID_PERS_ACCT_PERSON_ACCOUNT", nullable = false)
Long receiver;
In my RestController, i call this :
#RequestMapping(value = "/users/{id}", method = RequestMethod.GET)
public PersonAccount getUser(#PathVariable Long id) {
return userRepository.getOne(id);
}

Resources