Creating a native client

There are two ways to create a native client to communicate with an Elasticsearch server:

  • Creating a transport client: This is a standard client that requires the address and port of nodes to connect to.
  • Creating a client or coordinating only one node (it's a node that is not a data, master, or ingest node) and get the client from it. This node will appear in the cluster state nodes and can use the discovery capabilities of Elasticsearch to join the cluster (so no node address is required to connect to a cluster). This kind of client can reduce node routing due to knowledge of cluster topology. It can also load Elasticsearch plugins.

In this recipe, we will see how to create these clients.

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 natively supports it for Java programming such as Eclipse or IntelliJ IDEA, must be installed

The code for this recipe is in the chapter_14/nativeclient directory.

How to do it...

To create a native client, we will perform the following steps:

  1. Before starting, we must be sure that Maven loads the Elasticsearch JAR and the log4j required dependencies, by adding the following lines to the pom.xml:
            <dependency> 
                <groupId>org.elasticsearch.client</groupId> 
                <artifactId>transport</artifactId> 
                <version>5.0.0</version> 
            </dependency> 
            <dependency> 
                <groupId>org.apache.logging.log4j</groupId> 
                <artifactId>log4j-api</artifactId> 
                <version>2.6.2</version> 
            </dependency> 
            <dependency> 
                <groupId>org.apache.logging.log4j</groupId> 
                <artifactId>log4j-core</artifactId> 
                <version>2.6.2</version> 
            </dependency> 
    

    Note

    I always suggest using the latest available release of Elasticsearch or, in the case of a connection to a specific cluster, using the same version of Elasticsearch as the cluster is using. Native clients only work well if the client and the server have the same Elasticsearch version.

  2. We need to configure the logging by adding (as a resource) the log4j2.properties file with a similar content:
            appender.console.type = Console 
            appender.console.name = console 
            appender.console.layout.type = PatternLayout 
     
            rootLogger.level = info 
            rootLogger.appenderRef.console.ref = console 
    
  3. Now, to create a client, we have two ways:

    Getting the client from the transport protocol, which is the simplest way to get an Elasticsearch client:

            import org.elasticsearch.client.Client; 
            import org.elasticsearch.client.transport.TransportClient; 
            import org.elasticsearch.common.settings.Settings; 
            import 
            org.elasticsearch.common.transport.InetSocketTransportAddress; 
            import  
            org.elasticsearch.transport.client.PreBuiltTransportClient; 
     
            // on startup 
            final Settings settings = Settings.builder() 
                .put("client.transport.sniff", true) 
                .put("cluster.name", "elasticsearch").build(); 
            TransportClient client = new PreBuiltTransportClient(settings) 
                .addTransportAddress(new 
            InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 
            9300)); 
     
            // on shutdown 
            client.close(); 
    

    Getting the client from a node, which is quite tricky, because we need to define a PluginNode that loads the transport plugin and retrieve a connection from it:

            import org.elasticsearch.client.Client; 
            import org.elasticsearch.common.settings.Settings; 
            import org.elasticsearch.node.Node; 
     
            // on startup 
            private final Node node; 
            private final Client client; 
     
            private static class PluginNode extends Node { 
                public PluginNode(Settings preparedSettings, List<Class<?   
                extends Plugin>> plugins) { 
            super(InternalSettingsPreparer.prepareEnvironment
            (preparedSettings, null), plugins); 
                } 
            } 
     
            public NativeClient() throws NodeValidationException { 
                final Settings settings = Settings.builder() 
                        .put("path.home", "/tmp") 
                        .put("client.transport.sniff", true) 
                        .put("cluster.name", "elasticsearch") 
                        .put("node.data", false) 
                        .put("node.master", false) 
                        .put("node.ingest", false).build(); 
     
                node = new PluginNode(settings, Collections.<Class<? 
                extends Plugin>>singletonList(Netty4Plugin.class)); 
                node.start(); 
                client = node.client(); 
            } 
     
            // on shutdown 
            client.close(); 
            node.close(); 
    

How it works...

The steps to create a TransportClient are as follows:

  1. Create the settings required to configure the client. Typically, they hold the cluster name and some other options that we'll discuss later:
            final Settings settings = Settings.settingsBuilder() 
                            .put("client.transport.sniff", true) 
                            .put("cluster.name", "elasticsearch").build(); 
    
  2. Now we can create the client by passing it the settings, addresses, and port of our cluster:
            TransportClient client = new PreBuiltTransportClient(settings) 
                .addTransportAddress(new   
            InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 
            9300)); 
            ; 
    
  3. The addTransportAddress method can be called several times until all the required addresses and ports are set.

    Note

    The TransportClient method is the simplest way to create a native connection to an Elasticsearch server.

  4. Creating a node client is more complex as the new node becomes part of the cluster and we need to perform some tricks to load the transport plugin required for communication.
  5. In your Maven pom.xml the transport plugin must be defined as follows:
            <dependency>
              <groupId>org.elasticsearch.plugin</groupId>
              <artifactId>transport-netty4-client</artifactId>
              <version>5.0.0</version>
            </dependency>
  6. The standard node class doesn't have helpers for creating an Elasticsearch node with plugins, so we need a class helper PluginNode, which allows the transport plugin to be loaded:
            private static class PluginNode extends Node { 
                public PluginNode(Settings preparedSettings, List<Class<? 
                extends Plugin>> plugins) { 
                super(InternalSettingsPreparer.prepareEnvironment
               (preparedSettings, null), plugins); 
                } 
            } 
    
  7. Now we can define the settings needed to initialize node. We need to disable the master, data, and ingest functionalities:
            final Settings settings = Settings.builder() 
                    .put("path.home", "/tmp") 
                    .put("client.transport.sniff", true) 
                    .put("cluster.name", "elasticsearch") 
                    .put("node.data", false) 
                    .put("node.master", false) 
                    .put("node.ingest", false).build(); 
    
  8. After having defined the settings, we can build (by passing the transport plugin) and start our node:
            node = new PluginNode(settings, Collections.<Class<? extends       
            Plugin>>singletonList(Netty4Plugin.class)); 
            node.start(); 
    
  9. From the node object, client can be easily obtained:
            client = node.client(); 
    
  10. If client is retrieved from an embedded node, before closing the application, we need to free the resource needed by the node; this can be done by calling the close() method on the client and node:
            client.close();  
            node.close();  
    

The result is the same with both approaches to creating a native client--a working client allows the execution of native calls on an Elasticsearch server.

In both approaches, it is important to correctly define the name of the cluster, otherwise there are problems in node-joining or the transport client gives you a warning about invalid names.

There's more...

There are several settings that can be passed when creating a transport client. They are as follows:

  • client.transport.ignore_cluster_name: If you set it to true, the cluster name validation of connected nodes is ignored. This prevents a warning being printed if the client cluster name is different from the connected cluster name (default: false).
  • client.transport.ping_timeout: Every client pings the node to check its state. This value defines how much time it waits before a timeout (default: 5s).
  • client.transport.nodes_sampler_interval: This interval defines how often to sample/ping the nodes listed and connected. These pings reduce the failures if a node is down and allows the requests to be balanced with the available node  (default: 5s).

See also

..................Content has been hidden....................

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