How to Implement a QueryCommand

This section describes how to implement the query command using the SampleDriverQueryCommand.java code and the SampleSubnetGroupsCommand.java code.

Driver query command

The SampleDriverQueryCommand class inherits from the DriverQueryCommand class and implements the FieldOrdering interface.

public abstract class SampleDriverQueryCommand extends DriverQueryCommand implements FieldOrdering {

	protected SampleParams params;

	public SampleDriverQueryCommand(SampleParams params) {
		this.params = params;
	}

	protected abstract void run(ConnectProfile profile) throws IOException;

	@Override
	public void run() {
		for (ConnectProfile profile : params.getProfiles()) {
			if (isCancelRequested())
				return;

			try {
				run(profile);
			} catch (Throwable t) {
				String msg = String.format("%s (profile %s) error - %s", getName(), profile.getName(), t.getMessage());
				throw new IllegalStateException(msg, t);
			}
		}
	}

Among query commands, those that directly launch a thread by implementing run() as above are referred to as driver commands. There cannot be more than one driver command in a query: the driver command is placed at the front, and other commands leading to the pipe are executed as onPush() is called by the driver command's thread. Additional driver commands can be used in subqueries, such as join or union.

Query commands must be careful not to miss implementing cancel. Loops should continuously check to see if a cancel has been requested by the current user or system by calling isCancelRequested(), and if so, abort immediately.

As a parameter to the constructor, we are passed a SampleParams object, which is a class that inherits from ConnectProfileParams, so we can get a list of connect profile objects.

public String toString() {
    String s = getName();

    if (params.getName() != null)
        s += Strings.doubleQuote(params.getName());

    return s;
}

All query commands (QueryCommand) must implement toString(). The string representation of a QueryCommand must follows the valid query command syntax in a normalized form that can be re-parsed by the query parser.

This is because there is a step in generating the distributed query execution plan that converts the QueryCommand object back to a query string literal. If this implementation is missing, the execution plan will not display correctly, and the distributed query may fail.

Query command details

The SampleSubnetGroupsCommand inherits from the SampleDriverQueryCommand and implements the following methods:

  • getName(): Name of the query command.
  • getFieldOrder(): Field display order. If a field does not exist in the query results, it is ignored, which means that here you define a complete field order for the set of all possible field names that could be output. On the screen, the field output order of the last command that implements the FieldOrdering interface in the order of the query commands is applied.
  • run(): Implements a function to be executed by the thread of the driver command.

The example code uses the RestApiClient class to call the REST API and calls the pushPipe() method to output the result of the command. The parameters of pushPipe() use the Row class, which is an implementation of the Map interface, so you can pass variable key-value pairs. However, only the following types are allowed for values:

Java typeLogpresso typeDescription
java.lang.StringstringString
java.lang.Shortshort16bit integer number
java.lang.Integerint32bit integer number
java.lang.Longlong64bit integer
java.lang.Floatfloat32bit real number
java.lang.Doubledouble64bit real number
java.lang.BooleanboolBoolean
java.util.DatedateDate and time
java.net.Inet4Addressipv4IPv4 address
java.net.Inet6Addressipv6IPv6 address
java.util.ListlistList
java.util.MapmapMap. Only string type is allowed for key.
byte[]binaryByte array

If you need to process more than a few hundred thousand records per second, we recommend calling the pushPipe(VectorizedRowBatch) method to output the data. The following vector types can be used for the value of VectorizedRowBatch.

Vector typeLogpresso typeDescription
org.araqne.log.api.ObjectVectorobjectString or any types.
org.araqne.log.api.IntVectorintOptimized for 32bit integer number array.
org.araqne.log.api.LongVectorlongOptimized for 64bit integer number array.
org.araqne.log.api.DoubleVectordoubleOptimized for 64bit real number array.
org.araqne.log.api.BooleanVectorboolOptimized for boolean array.

Vectorizing and batching 1000 records reduces the overhead of calling the `pushPipe()' function by a factor of 1000, minimizes performance degradation due to lock contention, and reduces garbage collection, resulting in high performance.