Basically the sample code (attached) is a copy of DefaultFormatter with
some modifications to `formatEntry`

On Tue, Jul 16, 2019 at 6:13 PM Michael Wall <[email protected]> wrote:

> If you are still having issues, can you share your code?
>
> Mike
>
> On Tue, Jul 16, 2019 at 6:30 PM Christopher <[email protected]> wrote:
>
>> It's possible that the shell itself doesn't have it on its class path.
>> The output of the classpath command is probably the classpath of the
>> tabletserver you've connected to, not the current local shell process.
>>
>> Try `export CLASSPATH=path/to/MyFormatter.jar; bin/accumulo shell ...`
>>
>> On Tue, Jul 16, 2019 at 6:01 PM mhd wrk <[email protected]> wrote:
>> >
>> > Yes the jar is on all the tservers and I tried `config`command and
>> `formatter` commands as alternatives.
>> > Unfortunately no luck yet.
>> >
>> > On Tue, Jul 16, 2019 at 1:30 PM Michael Wall <[email protected]> wrote:
>> >>
>> >> Couple of thoughts
>> >>
>> >> 1 - Are you putting the jar on all the tservers and restarting
>> everthing?
>> >> 2 - Have you tried setting the formatter on the table as opposed to
>> the scan command.  Something like
>> >> 'config -t mytable -s table.formatter=com.example.MyFormatter'
>> >>
>> >> Mike
>> >>
>> >> On Tue, Jul 16, 2019 at 2:50 PM mhd wrk <[email protected]>
>> wrote:
>> >>>
>> >>> I'm trying to use a custom formatter with scan command in Accumulo
>> shell, but seems that scan simply ignores the custom formatter and uses the
>> default one!
>> >>>
>> >>> The steps I follow are:
>> >>>
>> >>> 1- Create custom Formatter by extending
>> org.apache.accumulo.core.util.format.Formatter
>> >>>
>> >>> 2- Copy the jar to ${ACCUMULO_HOME}/lib
>> >>>
>> >>> 3- Restart Accumulo to make sure everything is reloaded.
>> >>>
>> >>> 4- run `accumulo shell`
>> >>>
>> >>> 5- run `classpath` and confirm that the formatter jar is included in
>> the path.
>> >>>
>> >>> 5- `scan -f 50 -fm com.example.MyFormatter -st -t mytable`
>> >>>
>> >>>
>> >>> Accumulo version: 1.7.2
>> >>>
>> >>>
>> >>> Any known issues?
>> >>>
>> >>>
>> >>> Thanks,
>> >>>
>> >>> Mohammad
>> >>>
>> >>>
>> >>>
>>
>
package com.example;

import org.apache.accumulo.core.data.Key;
import org.apache.accumulo.core.data.Value;
import org.apache.accumulo.core.security.ColumnVisibility;
import org.apache.accumulo.core.util.format.Formatter;
import org.apache.hadoop.io.Text;

import java.text.DateFormat;
import java.text.FieldPosition;
import java.text.ParsePosition;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;

public class MyFormatter implements Formatter {

    private Iterator<Map.Entry<Key,Value>> si;
    private boolean doTimestamps;

    public static class DefaultDateFormat extends DateFormat {
        private static final long serialVersionUID = 1L;

        @Override
        public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) {
            toAppendTo.append(Long.toString(date.getTime()));
            return toAppendTo;
        }

        @Override
        public Date parse(String source, ParsePosition pos) {
            return new Date(Long.parseLong(source));
        }
    }

    private static final ThreadLocal<DateFormat> formatter = new ThreadLocal<DateFormat>() {
        @Override
        protected DateFormat initialValue() {
            return new DefaultDateFormat();
        }
    };

    @Override
    public void initialize(Iterable<Map.Entry<Key,Value>> scanner, boolean printTimestamps) {
        checkState(false);
        si = scanner.iterator();
        doTimestamps = printTimestamps;
    }

    @Override
    public boolean hasNext() {
        checkState(true);
        return si.hasNext();
    }

    @Override
    public String next() {
        DateFormat timestampFormat = null;

        if (doTimestamps) {
            timestampFormat = formatter.get();
        }

        return next(timestampFormat);
    }

    protected String next(DateFormat timestampFormat) {
        checkState(true);
        return formatEntry(si.next(), timestampFormat);
    }

    @Override
    public void remove() {
        checkState(true);
        si.remove();
    }

    protected void checkState(boolean expectInitialized) {
        if (expectInitialized && si == null)
            throw new IllegalStateException("Not initialized");
        if (!expectInitialized && si != null)
            throw new IllegalStateException("Already initialized");
    }

    /* so a new date object doesn't get created for every record in the scan result */
    private static ThreadLocal<Date> tmpDate = new ThreadLocal<Date>() {
        @Override
        protected Date initialValue() {
            return new Date();
        }
    };

    public static String formatEntry(Map.Entry<Key,Value> entry, DateFormat timestampFormat) {
        StringBuilder sb = new StringBuilder();
        Key key = entry.getKey();
        Text buffer = new Text();

        // append row
        Text row = key.getRow(buffer);
        sb.append("row_").append(appendBytes(sb, row.getBytes(), 0, row.getLength())).append(" ");

        // append column family
        Text cf = key.getColumnFamily(buffer);
        sb.append("cf_").append(appendBytes(sb, cf.getBytes(), 0, cf.getLength())).append(":");

        // append column qualifier
        Text cq = key.getColumnQualifier(buffer);
        sb.append("cq_").append(appendBytes(sb, cq.getBytes(), 0, cq.getLength()));

        // append visibility expression
        sb.append(new ColumnVisibility(key.getColumnVisibility(buffer)));

        // append timestamp
        if (timestampFormat != null) {
            tmpDate.get().setTime(entry.getKey().getTimestamp());
            sb.append(" ").append(timestampFormat.format(tmpDate.get()));
        }

        Value value = entry.getValue();

        // append value
        if (value != null && value.getSize() > 0) {
            sb.append("\t");
            appendValue(sb, value);
        }

        return sb.toString();
    }

    static StringBuilder appendValue(StringBuilder sb, Value value) {
        return appendBytes(sb, value.get(), 0, value.get().length);
    }

    static StringBuilder appendBytes(StringBuilder sb, byte ba[], int offset, int len) {
        for (int i = 0; i < len; i++) {
            int c = 0xff & ba[offset + i];
            if (c == '\\')
                sb.append("\\\\");
            else if (c >= 32 && c <= 126)
                sb.append((char) c);
            else
                sb.append("\\x").append(String.format("%02X", c));
        }
        return sb;
    }

    public Iterator<Map.Entry<Key,Value>> getScannerIterator() {
        return si;
    }

    protected boolean isDoTimestamps() {
        return doTimestamps;
    }
}

Reply via email to