Skip to content

Domain Object sample generation

bfemiano edited this page Sep 20, 2012 · 15 revisions

Many people will be interested in building their own cells to model domain objects. This is entirely possible with Cellmate.

Here's a PersonEnity POJO example.

@Cell
public class PersonEntity {

    private String name;
    private int age;
    private List<Relative> relatives = Lists.newArrayList();

    public PersonEntity() {}

    public void addRelative(Relative rel) {
        relatives.add(rel);
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public List<Relative> getRelatives() {
        return relatives;
    }

    public static class Relative {

        private String relationship;
        private String name;

        public Relative(String relationship, String name) {
            this.relationship = relationship;
            this.name = name;
        }

        public String getName() {
            return name;
        }

        public String getRelationship() {
            return relationship;
        }
    }
}

The class defines three fields.

  1. name stored as a String.
  2. age stored as an int
  3. A list of Relative objects. The Relative class is defined in a static inner class, and has two string fields, and name and the relationship to the containing PersonEntity.

Now lets assume this data exists in an Accumulo table named 'people'. The rowID defines all of what we know about a single person entity in the system. The people table defines two column familes. One for 'info' that contains the name and age, the other for 'relatives' that contained qualifiers describing the relationship and the name of the person as the value.

We can use the AccumuloDBResultReader and parameters to scan this table. We simply have to define a custom transformer to build our PersonEntity instances into a single CellGroup.

Here's how we do it. First we define our parameters object to scan the people table.

AccumuloParameters localParams = new AccumuloParameters.Builder().
                setUser("root").
                setPassword("password").
                setTable("people").
                setColumns(new String[]{"info:name", "info:age", "relatives"}).build();

We define our search to only look at the qualifiers 'name' and 'age' in the info column family, and everything in the 'relatives' column family.

Now let's make an anonymous transformer instance to create PersonEntity objects from incoming key/value entries from the scan.

List<CellGroup<PersonEntity>> items = reader.read(localParams, new CellTransformer<Map.Entry<Key, Value>, PersonEntity>() {
                    private String currentId = "";
                    private PersonEntity currentPerson;
                    public CellGroup<PersonEntity> apply(Map.Entry<Key, Value> entry, CellGroup<PersonEntity> group)
                            throws CellExtractorException {

                        String personId = entry.getKey().getRow().toString();
                        if(!personId.equals(currentId)) {
                            currentPerson = new PersonEntity();
                            group.addCell(currentPerson);
                        }
                        if(entry.getKey().getColumnFamily().toString().equals("relatives")) {
                            currentPerson.addRelative(new PersonEntity.Relative(
                                    entry.getKey().getColumnQualifier().toString(),
                                    entry.getValue().toString()));
                        } else {
                            if(entry.getKey().getColumnQualifier().toString().equals("name")) {
                                currentPerson.setName(entry.getValue().toString());
                            } else {
                                currentPerson.setAge(Integer.parseInt(entry.getValue().toString()));
                            }
                        }
                        currentId = personId;
                        return group;
                    }
                });

This short little block of code does everything we need it to. As the rowID changes we create a new PersonEntity object and add it to the cell group. The currentId is seto to blank "" so that we detect the first rowID in the scan. While the current rowID is equal to the active personId, we know there are still key/value pairs to process for that person. The following conditional checks to see if data came from the column family 'relatives' or 'info'. If the column family is 'info', set the currentPerson age or name depending on the qualifier. Otherwise we are looking at an entry from the column family 'relatatives' and want to create a new PersonEntity.Relative instance. The qualifer for the key is the relationship, and the value is the name of the relative. Add this PersonEntity.Relative instance to the list of relatives for the currentPerson. Always return the same CellGroup instance, we simply add new PersonEntity instances as key/value pairs are processed.

The output from reader.read() is a List<CellGroup> containing a single CellGroup. The internal list of cells for that CellGroup has all the PersonEntity objects we created in the transformer.

You can iterate through the items fairly easily assuming a single cell group.

for(PersonEntity person : items.get(0).getInternalList()){
    System.out.println("Person named: " + person.getName() + " is of age " + person.getAge());
    for(PersonEntity.Relative rel : person.getRelatives()) {
        System.out.println(" And is related to " + rel.getName() + " by relationship: " +  rel.getRelationship());
    }
}