Jest sort results by name - java

I have a Person index in my ElasticSearch database i get all the persons via this method:
public List<Person> findAll() {
SearchResult result = null;
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.matchAllQuery());
Search search = new Search.Builder(searchSourceBuilder.toString()).addIndex(PERSON_INDEX_NAME)
.addType(PERSON_TYPE_NAME).build();
try {
result = client.execute(search);
} catch (IOException e) {
}
List<SearchResult.Hit<Person, Void>> hits = result.getHits(Person.class);
return hits.stream().map(this::getPerson).collect(Collectors.toList());
}
but i want to get the results sorted alphabetically by name (person has String id and String name) but i cant figure out how.
any help is apreciated

What type is your name field?
The problem may be that ElasticSearch is splitting the name up into words, and then it can sort on any word. Which can give some pretty random looking results (e.g. the name "Zachary A. Zincstein" would come out highly, because it contains an "A").
A solution is to have a 2nd field, where you set type keyword in the mapping, and sort on that.

well.
i took the list given by ES and ordered it using the Collections sort method

Related

How do I find in Java a specific element, for printing, in a list of objects with multiple elements?

Long story short I parsed all the json from here
into a list of objects. But I'm having trouble trying to find a specific object. With all the examples on searching lists online I can't seem to be able to get it.
I ask the user to input a number into int checkId and checkUserId and then compare it. If it matches it should print out the title.
Iterator < Post > iter = posts.iterator();
while (iter.hasNext()) {
if (Objects.equals(iter.next().getUserId(), checkUserId)) {
System.out.println("found UserId");
if (Objects.equals(iter.next().getId(), checkId)) {
System.out.println("found Id");
//prints the title of object
}
}
}
And then I tried to use a stream
List<Post> result = posts.stream()
.filter(title -> checkId.equals(getId()))
.findAny()
.orElse(null);
All the code I cloned it from this great guy. https://github.com/danvega/httpclient-tutorial
Your first attempt does not work because you are advancing the iterator twice on each iteration by calling next. Instead, store the result of Iterator#next and use it.
Iterator<Post> iter = posts.iterator();
while(iter.hasNext()){
Post post = iter.next();
if(Objects.equals(post.getUserId(), checkUserId)) {
System.out.println("found UserId");
System.out.println(post.getTitle());
}
}
With streams:
List<String> titles = posts.stream().filter(post-> checkId.equals(post.getId()))
.map(Post::getTitle).collect(Collectors.toList());
titles.forEach(System.out::println);

implement tree iterator with JPA

I'm writing spring boot application. I have the HashTree structure, sorted by specific field. And I have a specific method that iterates through the tree, so if it finds a value (used as comparator) it returns it and does not check for other values.
With code it will look something like this:
class Storage {
TreeSet<Book> tree = new TreeSet<>(Comparator.comparingInt(Book::getNumberOfPages));
public Book getBookWithSmallestNumberOfPagesButGreaterThanSpecific(int number) {
iterator = tree.iterator();
while (iterator.hasNext()) {
Book book = iterator.next();
if (book.getNumberOfPages() > number) {
return book;
}
}
return null;
}
}
Please don't jurge that code, it's just for example, real code is much more complicated.
So I want to do the same thing using Spring JPA, and store Books in database.
My plan is:
create index on numberOfPages column in order to iterate it in asc order
get a coursor to the first database record
return current element or get next element in a cursor.
The thing is I dont know how to get a cursor, all JPA methods return all elements in a List<>.
Please challenge my solution. I don't know if I move in a right direction. I'm pretty new to JPA.
You can use Pageable,
Pageable pageable = PageRequest.of(page, size, direction, property);
List<ENTITY> findByProjectId(String projectId, Pageable pageable);

Spring-data-elasticsearch search for specific fields in multiple indices

I try to search specific fields in multiple indices. I have two indices country and region. Both of the indices have a Field called name.
I am able to specify my field name and my indices in my query using elasticsaerchTemplate:
#Override
public Page<SearchHit> searchAllTest(String text) {
QueryBuilder queryBuilder = QueryBuilders.boolQuery()
.should(QueryBuilders.queryStringQuery(text).field("name"));
NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
.withQuery(queryBuilder)
.withIndices("region", "country").build();
ResultsExtractor<Page<SearchHit>> rs = new ResultsExtractor<Page<SearchHit>>() {
#Override
public Page<SearchHit> extract(SearchResponse response) {
List<SearchHit> hits = Arrays.asList(response.getHits().getHits());
return new PageImpl<SearchHit>(hits, PageRequest.of(0, 10), response.getHits().getTotalHits());
}
};
return elasticsearchTemplate.query(nativeSearchQuery, rs);
}
This code works and searches for the field name in both of the indices. But I would like to specify the field name in index region and give for example a boost.
In simple words:
Field name belongs to index region and get a boost.
Field name belongs to index country and get no boost.
Is there a way to specify a field for a particular index?
Try to use withIndexBoost method:
NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
.withQuery(queryBuilder)
.withIndicesBoost(Arrays.asList(new IndexBoost[] {new IndexBoost("region", 2.0f)}))
.withIndices("region", "country").build();

Getting duplicate values while comparing with the map

Initially i will be selecting a list of student names in a page and submit for getting the address details.StudentNames will be stored in the studentDetailMapList.While looping through the list , i will compare the student names with the AddressDetailsMap to retrieve the addressDetails.But when there are students with same names , the first iteration returns the exact address but when the second iteration happens , it again returns the 1st student address instead of the second student address.It is getting the duplicate values
for (i=studentDetailMapList.values().iterator;i.hasNext();)
{
detailMap = (Map)i.Next();
sDetails = (StudentDetails)detailMap.get("Student");
student = sDetails.getRollNo();
StudentAddressDetails studentAddressDetails = getDetailswithAddress(AddressDetailsMap,sDetails);
}
private StudentAddressDetails getDetailswithAddress(Map AddressDetailsMap,sDetails student)
{
StudentAddressDetails addDetails = null;
try{
for(Iterator itr = AddressDetailsMap.values().iterator();itr.hasNext();){
addDetails = (StudentAddressDetails )itr.next();
if( (addDetails != null) && (addDetails.getStudentID().equals(student.getId()))){
return addDetails;
}
}
}catch(Throwable t){
return null;
}
return null;
}
Is there a way to avoid the duplicate while comparing with the map?
Thanks a lot.
The problem you are having is that you are using the the map data structure wrong.
A map is an object that maps keys to values. A map cannot contain duplicate keys; each key can map to at most one value.
You can not have multiple addresses for the same name, you should use other property for the map, maybe a Student ID, even the list's index should work in this case.
You have to add a UUID in your student's class and work with it for managing their data
EDIT for response
Java's UUID give you the basic Java's UUID.
you can manage your own sequence - This way may be helpfull for indexing Students in database with UNIQUE_ID.
The best thing to manage your IDs : use a HashMap<Integer,Student>.
Each key of your AddressDetailsMap map must be an identifier (studentId) and not the student name.
EDIT:
In this case, your method should look like this:
private StudentAddressDetails getDetailswithAddress(Map AddressDetailsMap,sDetails student) {
return AddressDetailsMap.get(student.getStudentID());
}

how to manipulate list in java

Edit: My list is sorted as it is coming from a DB
I have an ArrayList that has objects of class People. People has two properties: ssn and terminationReason. So my list looks like this
ArrayList:
ssn TerminatinoReason
123456789 Reason1
123456789 Reason2
123456789 Reason3
568956899 Reason2
000000001 Reason3
000000001 Reason2
I want to change this list up so that there are no duplicates and termination reasons are seperated by commas.
so above list would become
New ArrayList:
ssn TerminatinoReason
123456789 Reason1, Reason2, Reason3
568956899 Reason2
000000001 Reason3, Reason2
I have something going where I am looping through the original list and matching ssn's but it does not seem to work.
Can someone help?
Code I was using was:
String ssn = "";
Iterator it = results.iterator();
ArrayList newList = new ArrayList();
People ob;
while (it.hasNext())
{
ob = (People) it.next();
if (ssn.equalsIgnoreCase(""))
{
newList.add(ob);
ssn = ob.getSSN();
}
else if (ssn.equalsIgnoreCase(ob.getSSN()))
{
//should I get last object from new list and append this termination reason?
ob.getTerminationReason()
}
}
To me, this seems like a good case to use a Multimap, which would allow storing multiple values for a single key.
The Google Collections has a Multimap implementation.
This may mean that the Person object's ssn and terminationReason fields may have to be taken out to be a key and value, respectively. (And those fields will be assumed to be String.)
Basically, it can be used as follows:
Multimap<String, String> m = HashMultimap.create();
// In reality, the following would probably be iterating over the
// Person objects returned from the database, and calling the
// getSSN and getTerminationReasons methods.
m.put("0000001", "Reason1");
m.put("0000001", "Reason2");
m.put("0000001", "Reason3");
m.put("0000002", "Reason1");
m.put("0000002", "Reason2");
m.put("0000002", "Reason3");
for (String ssn : m.keySet())
{
// For each SSN, the termination reasons can be retrieved.
Collection<String> termReasonsList = m.get(ssn);
// Do something with the list of reasons.
}
If necessary, a comma-separated list of a Collection can be produced:
StringBuilder sb = new StringBuilder();
for (String reason : termReasonsList)
{
sb.append(reason);
sb.append(", ");
}
sb.delete(sb.length() - 2, sb.length());
String commaSepList = sb.toString();
This could once again be set to the terminationReason field.
An alternative, as Jonik mentioned in the comments, is to use the StringUtils.join method from Apache Commons Lang could be used to create a comma-separated list.
It should also be noted that the Multimap doesn't specify whether an implementation should or should not allow duplicate key/value pairs, so one should look at which type of Multimap to use.
In this example, the HashMultimap is a good choice, as it does not allow duplicate key/value pairs. This would automatically eliminate any duplicate reasons given for one specific person.
What you might need is a Hash. HashMap maybe usable.
Override equals() and hashCode() inside your People Class.
Make hashCode return the people (person) SSN. This way you will have all People objects with the same SSN in the same "bucket".
Keep in mind that the Map interface implementation classes use key/value pairs for holding your objects so you will have something like myHashMap.add("ssn",peopleobject);
List<People> newlst = new ArrayList<People>();
People last = null;
for (People p : listFromDB) {
if (last == null || !last.ssn.equals(p.ssn)) {
last = new People();
last.ssn = p.ssn;
last.terminationReason = "";
newlst.add(last);
}
if (last.terminationReason.length() > 0) {
last.terminationReason += ", ";
}
last.terminationReason += p.terminationReason;
}
And you get the aggregated list in newlst.
Update: If you are using MySQL, you can use the GROUP_CONCAT function to extract data in your required format. I don't know whether other DB engines have similar function or not.
Update 2: Removed the unnecessary sorting.
Two possible problems:
This won't work if your list isn't sorted
You aren't doing anything with ob.getTerminationReason(). I think you mean to add it to the previous object.
EDIT: Now that i see you´ve edited your question.
As your list is sorted, (by ssn I presume)
Integer currentSSN = null;
List<People> peoplelist = getSortedList();//gets sorted list from DB.
/*Uses foreach construct instead of iterators*/
for (People person:peopleList){
if (currentSSN != null && people.getSSN().equals(currentSSN)){
//same person
system.out.print(person.getReason()+" ");//writes termination reason
}
else{//person has changed. New row.
currentSSN = person.getSSN();
system.out.println(" ");//new row.
system.out.print(person.getSSN()+ " ");//writes row header.
}
}
If you don´t want to display the contents of your list, you could use it to create a MAP and then use it as shown below.
If your list is not sorted
Maybe you should try a different approach, using a Map. Here, ssn would be the key of the map, and values could be a list of People
Map<Integer,List<People>> mymap = getMap();//loads a Map from input data.
for(Integer ssn:mymap.keyset()){
dorow(ssn,mymap.get(ssn));
}
public void dorow(Integer ssn, List<People> reasons){
system.out.print(ssn+" ");
for (People people:reasons){
system.out.print(people.getTerminationReason()+" ");
}
system.out.println("-----");//row separator.
Last but not least, you should override your hashCode() and equals() method on People class.
for example
public void int hashcode(){
return 3*this.reason.hascode();
}

Categories

Resources