Elasticsearch part 6 [Nested Queries]

Lets first create the mapping, here in this tutorial we are using the example of book document which will contain he nested author field.

PUT /books/
{
    "mappings": {
        "book":{
            "properties": {
                "id":{
                    "type": "integer"
                },
                "title":{
                    "type": "string"
                },
                "categories":{
                    "type": "integer"
                },
                "tag":{
                    "type": "string"
                },
                "author":{
                    "type": "nested",
                    "properties": {
                        "firstname":{
                            "type": "string"
                        },
                        "lastname":{
                            "type": "string"
                        },
                        "id":{
                            "type": "integer"
                        }
                    }
                }
            }
        }
    }    
}

Here the type of author is nested which means it acts as object.
Note:: "nested" is more advanced form of "object" which allow us to put objects in the arrays.

Lets populate some data 

PUT /books/book/101
{
        "title" : "An article title",
        "categories" : [1,3,5,7],
        "tag" : ["elasticsearch", "symfony", "Obtao"],
        "author" : [
            {
                "firstname" : "Francois",
                "surname": "francoisg",
                "id" : 18
            },
            {
                "firstname" : "Gregory",
                "surname" : "gregquat",
                "id" : "2"
            }
        ]
}

PUT /books/book/102
{
        "title" : "Elasticsearch",
        "categories" : [1,3,5,7],
        "tag" : ["elasticsearch", "bigdate", "Text search"],
        "author" : [
            {
                "firstname" : "yubraj",
                "surname": "pokharel",
                "id" : 18
            },
            {
                "firstname" : "dharma",
                "surname" : "kshetri",
                "id" : "2"
            }
        ]
}

Now lets say we need those books whose author name is yubraj pokharel ( thats me ;) ) so what we do now umm lets try some queries


GET /books/book/_search
{
  "query": {
    "filtered": {
      "query": {
        "match_all": {}
      },
      "filter": {
        "nested" : {
          "path" : "author",
          "filter":{
              "bool": {
                  "must": [
                     {
                         "term": {
                            "author.firstname": "yubraj"
                         }
                     },
                     {
                         "term": {
                            "author.surname": "pokharel"
                         }
                     }
                  ]
              }
          }
        }
      }
    }
  }
}


so the output will be 

{
   "took": 29,
   "timed_out": false,
   "_shards": {
      "total": 5,
      "successful": 5,
      "failed": 0
   },
   "hits": {
      "total": 1,
      "max_score": 1,
      "hits": [
         {
            "_index": "books",
            "_type": "book",
            "_id": "102",
            "_score": 1,
            "_source": {
               "title": "Elasticsearch",
               "categories": [
                  1,
                  3,
                  5,
                  7
               ],
               "tag": [
                  "elasticsearch",
                  "bigdate",
                  "Text search"
               ],
               "author": [
                  {
                     "firstname": "yubraj",
                     "surname": "pokharel",
                     "id": 18
                  },
                  {
                     "firstname": "dharma",
                     "surname": "kshetri",
                     "id": "2"
                  }
               ]
            }
         }
      ]
   }
}

OR you can also use the query like this

GET /books/book/_search
{
    "query": {
        "bool": {
            "must": [
               {
                "match": {
                   "title": "elasticsearch"
                }
               },
               {
                   "nested": {
                      "path": "author",
                      "query": {
                          "bool": {
                              "must": [
                                 {
                                     "term": {"author.firstname": {"value": "yubraj"}}
                                 },
                                 {
                                     "term": {"author.surname": {"value": "pokharel"}}
                                 }
                              ]
                          }
                      }
                   }
               }
            ]
        }
    }

}



ElasticSearch Part 5 [Selecting Shards Algorithm]

Let me explain this in the natural language. Lets suppose there are 10 shards across all the network, and we need to write a document in the shard. And you start to think about it like how should I select the shards to which we need to write. Don't worry it can ES can select the shards randomly. Yes you think you are smart? think again what will happen when you want to retrieve the data again do you want to use random again fuck no because it may not get the required data in the random shards we pick.

Don't worry there is a algorithm that is used by the partitioner in the ES which determines the shards where we need to write the document. For this the document id is used.

shard = hash(routing) % number_of_primary_shards

here routing value is the arbitrary string which by default is the doc_id. Lets take a example to understand it. Let us suppose we have 10 shards all across the network and we want to put a user detail in one of the shards. Let user doc_id be 100 and after hashing we get some number like 66 then

shard = 66 % 10 = 6

hence the partitioner will write this document in the shard with index 6 i.e. the 7th one. And also use the same algorithm to retrieve it. In the above process the remainder will always be in the range of 0 to number_of_primary_shards -1.

But there is some drawbacks in the scaling of ES. Users sometimes think that having a fixed number of primary shards makes it difficult to scale out an index later. In reality, there are techniques that make it easy to scale out as and when you need. For this we need to re-index all the data and there are some techniques to do it which we will discuss in later post.

ElasticSearch Part 4 [Advanced Query]

lets focus in the Query string what we can achieve and how we can perform advanced queries using the query string

1. +/- Operators: This helps us to filter the words during the search. Let us take an example:
GET /ecommerce/product/_search?q=(name:(+dell)
in the above query the name feild must contain the dell word

GET /ecommerce/product/_search?q=(name:(+dell -hp))
in the above query the name field must contain the dell word and must not contain any hp word

2. Boolean Operators:: lets say we want to search the product with
  - name as "dell"
  - must have status active i.e. 1
  - which description must contain the word "code"

so we will do it by
GET /ecommerce/product/_search?q=(name:(+dell -hp) AND status:1 AND description:+code)


ElasticSearch Part 3 [Categories of Queries]


In elasticsearch there are two main categories in queries which are :

1. Leaf: It looks for particular value in particular fields like "dell" in the product name. This queries can be used by themselves without being part of the compound queries. And the best thing is it can be used as a part of compound query too for the most advanced queries.

2. Compound: This queries wrap the leaf queries and can wrap other compound queries. It combine multiple queries in logical fashion which means as a Boolean logic. Using this we can also alter the behavior of the queries.

3. Full Text: It is used for running full text search query i.e. looking for every fields in the document. Here values are analyzed when adding and updating the document. It is analyzed like by using the stop words like "the".

4. Term Value: Used to match exact matching values. Usually used for the numbers and date rather then the text. E.g. Finding peoples who are born between 2001 and 2010. Here search queries are not analyzed before executing.

5. Joining Queries: As we know that it is very expensive to perform joining in the distributed system so elasticsearch offers two forms of joins that are designed to scale horizontally they are:

I. Nested Queries
Lets go back, where we had defined a propertise called category in the product document which contains the array of the categories. This nested queries are used in such situation where each object can be queried as a nested query as a indepedent query. 

II. has_child and has_parent queries
has_child returns the parent document which child document match the query similarly has_parent returns the child document which parent document match the query.

6. Geo Queries
I. geo_point:: it is used for latitute/longitude pairs

II. geo_shape:: it is used for the shapes like triangle, polygons etc.

ElasticSearch Part 2 [Searching]

Lets populate some products first: 

PUT /ecommerce/product/1002
{
    "name": "Dell",
    "price": 1200.00,
    "description": "This product is awesome and I love to code in it",
    "status": 1,
    "quantity": 2,
    "categories": [
        {"name":"dell"},
        {"name":"laptop"}
        ],
    "tags":["dell", "programming", "laptop"]
}

PUT /ecommerce/product/1003
{
    "name": "Dell",
    "price": 1200.00,
    "description": "This product is awesome and I love to design in it",
    "status": 1,
    "quantity": 2,
    "categories": [
        {"name":"dell"},
        {"name":"laptop"}
        ],
    "tags":["dell", "desigining", "laptop"]
}

In the previous post I have explained about how to create, update, read and deleting the documents in ElasticSearch. Now lets talk about Searching, Oh yeah! searching for which ElasticSearch is best about. Basically there are two ways of searching techniques which are: Query String and Query DSL. But lets talk about some basic stuff that we need to know before starting Search.

Relevancy and Scoring: To rank document for query, a score is calculated for each document that matches a query. Which means the higher the search score the document is more relevant to search query.

1. Query String: Its done using the search parameter in the URI through the rest request. It is specilly used for simple queries as well as for ad-hoc. e.g.

GET https://localhost/ecommerce/product/_serarch?q=dell
GET https://localhost/ecommerce/product/_serarch?q=name:dell &desc:"SOME_TEXT"
GET https://localhost/ecommerce/product/_serarch?q=(name:(dell OR hp) AND status:1)

Here all fields are searched for the word "dell" by default.

NOTE :: _search is a API used to perform a search process and q is the query parameter

and the output will be: 

{
   "took": 30,
   "timed_out": false,
   "_shards": {
      "total": 5,
      "successful": 5,
      "failed": 0
   },
   "hits": {
      "total": 1,
      "max_score": 0.3074455,
      "hits": [
         {
            "_index": "ecommerce",
            "_type": "product",
            "_id": "1003",
            "_score": 0.3074455,
            "_source": {
               "name": "Dell",
               "price": 1200,
               "description": "This product is awesome and I love to design in it",
               "status": 1,
               "quantity": 2,
               "categories": [
                  {
                     "name": "dell"
                  },
                  {
                     "name": "laptop"
                  }
               ],
               "tags": [
                  "dell",
                  "desigining",
                  "laptop"
               ]
            }
         }
      ]
   }
}


2. Query DSL :: In this technique the queries are defined within the request body of the JSON. It supports more feature then the query string approach. Its often easier to read and also we can perform more advanced queries. e.g.

GET /ecommerce/product/_search
{
    "query": {
        "filtered": {
           "filter": {
               "range": {
                  "price": {
                     "from": 1000,
                     "to": 2000
                  }
               }
           },
           "query": {
               "query_string": {
                  "fields": ["tags"],
                  "query": "laptop",
                  "query": "hp"
               }
           }
        }
    }
}

In the above query it will first filter the products having the price in between 1000 to 2000 and then looks up for the words laptop and hp in the tags field.

GET /ecommerce/product/_search
{
    "query": {
        "match": {
           "name": "dell"
        }
    }
}

and the result will be

{
   "took": 664,
   "timed_out": false,
   "_shards": {
      "total": 5,
      "successful": 5,
      "failed": 0
   },
   "hits": {
      "total": 2,
      "max_score": 1.4054651,
      "hits": [
         {
            "_index": "ecommerce",
            "_type": "product",
            "_id": "1003",
            "_score": 1.4054651,
            "_source": {
               "name": "Dell",
               "price": 1200,
               "description": "This product is awesome and I love to design in it",
               "status": 1,
               "quantity": 2,
               "categories": [
                  {
                     "name": "dell"
                  },
                  {
                     "name": "laptop"
                  }
               ],
               "tags": [
                  "dell",
                  "desigining",
                  "laptop"
               ]
            }
         },
         {
            "_index": "ecommerce",
            "_type": "product",
            "_id": "1002",
            "_score": 1.4054651,
            "_source": {
               "name": "Dell",
               "price": 1200,
               "description": "This product is awesome and I love to code in it",
               "status": 1,
               "quantity": 2,
               "categories": [
                  {
                     "name": "dell"
                  },
                  {
                     "name": "laptop"
                  }
               ],
               "tags": [
                  "dell",
                  "programming",
                  "laptop"
               ]
            }
         }
      ]
   }
}

ElasticSearch Part 1 [Mappings]


For this tutorial we are using the "Sense - a Json aware interface to ElasticSearch"

1. creating a index in elasticsearch
PUT /ecommerce {}


2. creating a mapping named product
PUT /ecommerce/
{
    "mappings": {
        "product":{
            "properties": {
                "name":{
                    "type": "string"
                },
                "price":{
                    "type": "double"
                },
                "description":{
                    "type": "string"
                },
                "quantity":{
                  "type":"string"
                },
                "status":{
                    "type": "integer"
                },
                "categories":{
                    "type": "nested",
                    "properties": {
                        "name":{
                            "type": "string"
                        }
                    }
                },
                "tags":{
                    "type": "string"
                }
            }
        }
    }
}


3. putting data in the schema with id 1001

PUT /ecommerce/product/1001
{
    "name": "Inception Innovation Center",
    "price": 120.00,
    "description": "Welcome to heaven of code",
    "status": 1,
    "quantity": 2,
    "categories": [
        {"name":"innovation"},
        {"name":"programming"}
        ],
    "tags":["inception", "programming"]
}


4. Getting the item info having ID 1001
GET /ecommerce/product/1001
{
   "_index": "ecommerce",
   "_type": "product",
   "_id": "1001",
   "_version": 1,
   "found": true,
   "_source": {
      "name": "Inception Innovation Center",
      "price": 120,
      "description": "Welcome to heaven of code",
      "status": 1,
      "quantity": 2,
      "categories": [
         {
            "name": "innovation"
         },
         {
            "name": "programming"
         }
      ],
      "tags": [
         "inception",
         "programming"
      ]
   }
}

5. Lets say we want to update the above doc with one more category then what we need to do is 

POST /ecommerce/product/1001/_update
{
  "doc":{
         "categories": [
                {"name":"innovation"},
                {"name":"programming"},
                {"name":"inception"}
            ]
  }
}

here doc represent the the key-value pair of fields that needs to be update. Its a simple way to update and there is also another way to update for that we need to write entire properties like:

PUT /ecommerce/product/1001
{
    "name": "Inception Innovation Center",
    "price": 120.00,
    "description": "Welcome to heaven of code",
    "status": 1,
    "quantity": 2,
    "categories": [
                {"name":"innovation"},
                {"name":"programming"},
                {"name":"inception"}
            ],
    "tags":["inception", "programming"]
}

among this this I prefer the first one. The main advantage of second one is, if there is no product with id 1001 then it will create a new product with the specified id, which means there will be no data loss.
And the following is the output

{
   "_index": "ecommerce",
   "_type": "product",
   "_id": "1001",
   "_version": 2,
   "found": true,
   "_source": {
      "name": "Inception Innovation Center",
      "price": 120,
      "description": "Welcome to heaven of code",
      "status": 1,
      "quantity": 2,
      "categories": [
         {
            "name": "innovation"
         },
         {
            "name": "programming"
         },
         {
            "name": "inception"
         }
      ],
      "tags": [
         "inception",
         "programming"
      ]
   }
}

.Here the version of the doc has been changed.

HTML Headings

Headings are defined with the <h1> to <h6> tags.
<h1> defines the most important heading. <h6> defines the least important heading.

This is heading 1

This is heading 2

This is heading 3

This is heading 4

This is heading 5
This is heading 6

FIZZBUZZ Solution in Java 8

Here is the FizzBuzz Solution in java 8 with different methods,

Here is the Before Java 8, simple solution:


public static void main(String[] args){
  for(int i= 1; i <= 20; i++){
   if(i % 15 == 0){
    System.out.println("FizzBuzz");
   }else if(i % 3 == 0){
    System.out.println("Fizz");
   }else if(i % 5 == 0){
    System.out.println("Buzz");
   }else{
    System.out.println(i);
   }
  }
 }


Now, Using Stream API, here different methods to display solved fizzbuzz solution,

Method1:
public static void main(String[] args) {
         fizzBuzzDisplay(1, 20;
  }
  private static void fizzBuzzDisplay(int i, int j) {
    // TODO Auto-generated method stub
           IntStream.rangeClosed(i,j)
                          .mapToObj(Test::transformNr)
                          .forEach(System.out::println);
   }

Method 2:
public static void main(String[] args) {
  // TODO Auto-generated method stub
  IntStream.rangeClosed(1, 20).mapToObj(num -> getWordForNum(num).orElse(Integer.toString(num)))
  .forEach(System.out::println);
 }
 private static Optional<String> getWordForNum(int num) {
  String word = "";
  if (isDiv(3).test(num))
   word += "Fizz";
  if (isDiv(5).test(num))
   word += "Buzz";
  return "".equals(word) ? Optional.empty() : Optional.of(word);
 }

 private static IntPredicate isDiv(int factor) {
  return arg -> (arg % factor) == 0;
 }

Method 3:
public static void main(String[] args) {
  // TODO Auto-generated method stub
  IntStream.rangeClosed(1, 20).mapToObj(A::fizzBuzz).forEach(System.out::println);
 }
 public static String fizzBuzz(int number) {
  if (number % 3==0 && number % 5 == 0) {
   return "FizzBuzz";
  } else if (number % 3 == 0) {
   return "Fizz";
  } else if (number % 5 == 0) {
   return "Buzz";
  }
  return Integer.toString(number);
 }

Method 4:
public static void main(String[] args) {
  // TODO Auto-generated method stub
  IntStream.range(1, 20)
        .mapToObj(n -> {
            if (n % 15 == 0) return "FizzBuzz";
            else if (n % 3 == 0) return "Fizz";
            else if (n % 5 == 0) return "Buzz";
            else return n;
        }).forEach(System.out::println);
 }

Mehtod 5:
public static void main(String[] args) {
  // TODO Auto-generated method stub
  IntStream.range(1, 20)
        .boxed()
        .map(x -> x+": " + (x%3==0? "Fizz": "") + (x%5==0? "Buzz": ""))
        .forEach(System.out::println);
 }

Output:

1
2
fizz
4
buzz
fizz
7
8
fizz
buzz
11
fizz
13
14
fizzbuzz
16
17
fizz
19
buzz

Happy Coding !!!

Print all the names of student in alphabetical order by gender in java 8 using Stream API

This question is some tricky, you have to create enum and student class then sorted the predefined condition in question.

Enum of Gender
public enum Gender {
 MALE,FEMALE;

}


Person Class with getter , setter and override to string method.
public class Person {
 
 public Gender getGender() {
  return gender;
 }
 public void setGender(Gender gender) {
  this.gender = gender;
 }
 public Person(String fn, String ln, Gender g){
  
  this.fName=fn;
  this.lName=ln;
  this.gender=g;
  
 }
 public String getfName() {
  return fName;
 }
 public void setfName(String fName) {
  this.fName = fName;
 }
 public String getlName() {
  return lName;
 }
 public void setlName(String lName) {
  this.lName = lName;
 }
 public String fName;
 public String lName;
 public Gender gender;
 
 public String getName(){
  return getfName()+" "+getlName();
 }
 
@Override
public String toString() {
 return  getfName()+" "+getlName();
}

}


and create person and display names

public static void main(String[] args) {
  // TODO Auto-generated method stub

    List<Person> persons=new ArrayList<>();
    persons.add(new Person("Arnolad", "Jones", Gender.MALE));
    persons.add(new Person("Zack", "Jones", Gender.MALE));
    persons.add(new Person("Mary", "Jones", Gender.FEMALE));
    persons.add(new Person("Anna", "Jones", Gender.FEMALE));
    
    System.out.println(persons.stream()
                        .sorted((p1,p2)->p1.getName().compareTo(p2.getName()))
                        .collect(Collectors.groupingBy(Person::getGender))
                        
      );
    
    
 }


Output:
{FEMALE=[Anna Jones, Mary Jones], MALE=[Arnolad Jones, Zack Jones]}

Happy Coding!!!


Combine different list in to Set(single list) in Java 8 using Stream API

Combine the different list in to single list in java, there should be used in java 8 Creating a stream pipeline that transforms a list of sets (of type String) into the union of those
sets. Make use of the reduce method for streams.
Example:
Orginal list [{“A”, “B”}, {“D”}, {“1”, “3”, “5”}] to the
Final Set
{“A”, “B”, “D”, “1”, “3”, “5”}.

Code looks like:
public class Union {

    public static void main(String[] args) {
        List<Set<String>> list = new ArrayList<>();
        Set<String> set1 = new LinkedHashSet<>(Arrays.asList(new String[]{"A", "B"}));
        list.add(set1);

        Set<String> set2 = new LinkedHashSet<>(Arrays.asList(new String[]{"D"}));
        list.add(set2);

        Set<String> set3 = new LinkedHashSet<>(Arrays.asList(new String[]{"1", "2", "3"}));
        list.add(set3);

        System.out.println("input: " + list);

        System.out.println("output:" + combinedList(list));

    }

    public static Set<String> combinedList(List<Set<String>> sets) {
        Optional<Set<String>> stream = sets.stream().reduce((t, u) -> {
            t.addAll(u);
            return t;
        });

        return stream.get();
    }
}



Happy Coding !!!

Sub List or partition list according to index in java 8 using Stream API

Question is like this, Create a method Stream<String> streamSection(Stream<String> stream, int m, int n) which extracts a substream from the input stream stream consisting of all elements from position m to position n , inclusive; you must use only Stream operations to do this. You can assume 0 <= m <= n .

Solution:
public class Section {

    public static Stream<String> streamSection(Stream<String> stream, int m, int n) {

        return stream.skip(m).limit(n - m + 1);
        

    }

    public static void main(String[] args) {

        System.out.println(streamSection(nextStream(), 0, 3).collect(Collectors.joining(", ")));
        System.out.println(streamSection(nextStream(), 2, 5).collect(Collectors.joining(", ")));
        System.out.println(streamSection(nextStream(), 7, 8).collect(Collectors.joining(", ")));
    }

    //support method for the main method -- for testing
    private static Stream<String> nextStream() {
        return Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii").stream();

    }

}

Output:
aaa, bbb, ccc
eee, fff, ggg, hhh, iii
ccc, ddd, eee, fff, ggg, hhh


Happy Coding !!!

Print Square in Java Using Lambda or Stream API

Creates an IntStream using the iterate method. The method prints to the console the
first num squares. For instance, if num = 4, then your method would output 1, 4, 9, 16. Note:
You will need to come up with a function to be used in the second argument of iterate .


public class Test {

 public static void main(String[] args) {
  // TODO Auto-generated method stub

   System.out.println(printSSquare(5));
  //printSSquare(5).forEach(System.out::print);
    printUsingSream(5);
    
    
 }
 
 //Using java 8
 private static void printUsingSream(int ns) {
  // TODO Auto-generated method stub
  IntStream intS=IntStream.iterate(1, n->n+1).map(i->i*i).limit(ns);
  intS.forEach(System.out::println);
  
  
 }

    // Old techniques , Previous java 8
 private static List<Integer> printSSquare(int i) {
  
  List<Integer> test= new ArrayList<>();
  // TODO Auto-generated method stub
  for (int j = 1; j <= i; j++) {
   test.add(j*j);
   
  }
  return test;
 }

}




Output :

[1, 4, 9, 16, 25]
1
4
9
16
25

Happy Coding !!!