Managing documents

The APIs for managing documents (index, delete, and update) are the most important after the search ones. In this recipe, we will see how to use them.

Getting ready

You need an up-and-running Elasticsearch installation, as we described in the Downloading and installing Elasticsearch recipe in Chapter 2, Downloading and Setup.

A Maven tool, or an IDE that supports Scala programming, such as Eclipse (ScalaIDE) or IntelliJ IDEA, with the Scala plugin should be installed.

The code of this recipe can be found in the chapter_15/elastic4s_sample file and the referred class is DocumentExample.

How to do it...

For managing documents, we will perform the following steps:

  1. We'll need to import the required classes to execute all the document CRUD operations:
            import com.sksamuel.elastic4s.ElasticDsl._ 
    
  2. We create the client and ensure that the index and mapping exists:
            object DocumentExample extends App with 
            ElasticSearchClientTrait{ 
            val indexName="myindex" 
            val typeName="mytype" 
     
            ensureIndexMapping(indexName, typeName) 
    
  3. Now, we can store a document in Elasticsearch via the indexInto call:
            client.execute { 
            indexInto(indexName / typeName) id "0" fields ( 
                "name" -> "brown", 
              "tag" -> List("nice", "simple") 
             ) 
           }.await  
    
  4. We can retrieve the stored document via the get call:
                val bwn=client.execute { 
            get("0") from indexName / typeName 
            }.await 
      
          println(bwn.sourceAsString) 
    
  5. We can update the stored document via the update call using a script in Painless:
            client.execute { 
                update("0").in(indexName / 
                typeName).script("ctx._source.name = 'red'") 
             }.await 
    
  6. We can check if our update was applied:
            val red=client.execute { 
                get("0") from indexName / typeName 
              }.await 
     
              println(red.sourceAsString) 
    
  7. The console output result will be:
            no modules loaded
            loaded plugin [org.elasticsearch.index.reindex.ReindexPlugin]
            loaded plugin [org.elasticsearch.percolator.PercolatorPlugin]
            loaded plugin 
            [org.elasticsearch.script.mustache.MustachePlugin]
            loaded plugin [org.elasticsearch.transport.Netty3Plugin]
            loaded plugin [org.elasticsearch.transport.Netty4Plugin]
            {"name":"brown","tag":["nice","simple"]}
            {"name":"red","tag":["nice","simple"]}
    

The document version, following an update action and if the document is re-indexed with new changes, is always incremented by 1.

How it works...

Before executing a document action, a client and the index must be available and document mapping should be created (the mapping is optional, because it can be inferred from the indexed document).

To index a document, elastic4s allows us to provide the document content in several ways, such as via:

  • fields:
    • A sequence of tuples (String, Any) as in the preceding example
    • Map[String, Any]
    • An Iterable[(String, Any)]
  • doc/source:
    • A string
    • A typeclass that derives Indexable[T]

Obviously, it's possible to add all the parameters that we saw in the Indexing a document recipe in Chapter 4, Basic Operations, such as parent, routing, and so on.

The return value, IndexReponse, is the same retuned object from the Java call.

To retrieve a document, we need to know the index/type/id; the method is get. It requires the id and the index, type provided in the from method. A lot of other methods are available to control the routing (such as souring, parent) or fields as we have seen in the Getting a document recipe in Chapter 4, Basic Operations. In the preceding example, the call is:

 val bwn=client.execute { 
    get("0") from indexName / typeName 
  }.await 

The return type, GetResponse, contains all the requests (if the document exists) and the document information (source, version, index, type, and id).

To update a document, it's required to know the index/type/id and provide a script or a document to be used for the update. The client method is update. In the preceding example, we have used a script:

client.execute { 
    update("0").in(indexName / typeName).script("ctx._source.name = 'red'") 
  }.await 

The script code must be a string. If the script language is not defined, the default Painless is used.

The returned response contains information about the execution and the new version value to manage concurrency.

To delete a document (without the need to execute a query), we must know the index/type/id and we can use the client method, delete, to create a delete request. In the preceding code, we have used:

client.execute { 
    delete("0") from indexName / typeName 
  }.await 

The delete request allows  all the parameters we saw in the Deleting a document recipe in Chapter 4, Basic Operations, to control routing and versions, to be passed to it.

There's more...

Scala programmers love typeclass, automatic marshalling/unmarshalling from case classes, and a strong type management of the data. For this, elastics4 provides additional support for the common JSON serialization library, such as:

         "com.sksamuel.elastic4s" %% "elastic4s-circe" % elastic4sV 
        "com.sksamuel.elastic4s" %% "elastic4s-jackson" % elastic4sV 
        "com.sksamuel.elastic4s" %% "elastic4s-json4s" % elastic4sV 

For example, if you want to use Circe, perform the following steps:

  1. You need to import the circe implicits:
            import com.sksamuel.elastic4s.circe._ 
            import io.circe.generic.auto._ 
            import com.sksamuel.elastic4s.Indexable 
    
  2. You need to define the case class that needs to be deserialized:
            case class Place(id: Int, name: String) 
    
  3. You need to force the implicit serializer:
            implicitly[Indexable[Cafe]] 
    
  4. Now you can index the case classes directly:
            val cafe=Cafe("nespresso", Place(20,"Milan")) 
     
            client.execute { 
              indexInto(indexName / typeName).id(cafe.name).source(cafe) 
            }.await 
       
    

See also

In the recipes, we have used all CRUD operations on a document. For more details about these actions, refers to:

  • The Indexing a document recipe in Chapter 4, Basic Operations
  • The Getting a document recipe in Chapter 4, Basic Operations, on retrieving a stored document
  • The Deleting a document recipe in Chapter 4, Basic Operations
  • The Updating a document recipe in Chapter 4, Basic Operations
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.129.208.25