快速查找hazelcast列表中的条目

时间:2016-12-29 07:04:52

标签: list hazelcast predicate

我有一个hazelcast Ilist,学生班包含5个属性,如(id,姓名,地址,号码,学校)。现在列表中有10k条记录,我怎样才能找到名字为tony且号码为的学生除了for循环之外,我很快就会知道。我知道如果它是一个Imap我可以使用谓词来过滤,但它是一个列表,我没有找到Ilist.Any帮助的谓词,非常感谢。

2 个答案:

答案 0 :(得分:1)

不幸的是,没有办法用某种谓词或其他魔法来做到这一点。你必须做一个循环。但是,要加快速度,您应该在包含列表的成员上运行此搜索。但是,分区由列表的名称定义。您基本上可以自己编写一个小的“查询引擎”,以便在列表顶部使用Hazelcast谓词。

我创建了一个基本示例,但您最有可能优化它。

一个简单的学生班:

public class Student implements Serializable {
    private long id;
    private String name;
    private String address;
    private String number;
    private String school;

    public long getId() { return id; }

    public void setId(long id) { this.id = id; }

    public String getName() { return name; }

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

    public String getAddress() { return address; }

    public void setAddress(String address) { this.address = address; }

    public String getNumber() { return number; }

    public void setNumber(String number) { this.number = number; }

    public String getSchool() { return school; }

    public void setSchool(String school) { this.school = school; }

    @Override
    public String toString() {
        return "Student{" + "id=" + id
            + ", name='" + name + '\''
            + ", address='" + address + '\''
            + ", number='" + number + '\''
            + ", school='" + school + '\'' + '}';
    }
}

搜索执行者:

public class StudentSearch {

    private final IExecutorService executorService;

    public StudentSearch(HazelcastInstance hazelcastInstance) {
        this.executorService = 
            hazelcastInstance.getExecutorService("student_search");
    }

    public Student findFirstByNameAndNumber(String listName,
                                            String name,
                                            String number)
            throws Exception {
        Predicate namePredicate = Predicates.equal("name", name);
        Predicate numberPredicate = Predicates.equal("number", number);
        Predicate predicate = Predicates.and(namePredicate, numberPredicate);

        StudentSearchTask task = new StudentSearchTask(listName, predicate);
        Future<Student> future = executorService.submitToKeyOwner(task, listName);
        return future.get();
    }

    private static class StudentSearchTask
            implements Callable<Student>,
                       DataSerializable,
                       HazelcastInstanceAware {

        private HazelcastInstance hazelcastInstance;

        private String listName;
        private Predicate predicate;

        public StudentSearchTask() {
        }

        public StudentSearchTask(String listName, Predicate predicate) {
            this.listName = listName;
            this.predicate = predicate;
        }

        @Override
        public void setHazelcastInstance(HazelcastInstance hazelcastInstance) {
            this.hazelcastInstance = hazelcastInstance;
        }

        @Override
        public Student call() throws Exception {
            IList<Student> list = hazelcastInstance.getList(listName);
            Optional<Map.Entry<String, Student>> first =
                list.stream()
                    .map(this::makeMapEntry)
                    .filter(predicate::apply)
                    .findFirst();

            return first.orElse(makeMapEntry(null)).getValue();
        }

        @Override
        public void writeData(ObjectDataOutput out) throws IOException {
            out.writeUTF(listName);
            out.writeObject(predicate);
        }

        @Override
        public void readData(ObjectDataInput in) throws IOException {
            listName = in.readUTF();
            predicate = in.readObject();
        }

        private Map.Entry<String, Student> makeMapEntry(Student student) {
            return new QueryEntry(listName, student);
        }
    }

    // Used to query the list entries
    private static class QueryEntry
            implements Map.Entry<String, Student>,
                       Extractable {

        private final String key;
        private final Student value;

        private QueryEntry(String key, Student value) {
            this.key = key;
            this.value = value;
        }

        @Override
        public Object getAttributeValue(String attributeName)
                throws QueryException {
            if ("number".equals(attributeName)) {
                return value.getNumber();
            } else if ("name".equals(attributeName)) {
                return value.getName();
            }
            return null;
        }

        @Override
        public AttributeType getAttributeType(String attributeName) 
                throws QueryException {
            return AttributeType.STRING;
        }

        @Override
        public String getKey() {
            return key;
        }

        @Override
        public Student getValue() {
            return value;
        }

        @Override
        public Student setValue(Student value) {
            throw new UnsupportedOperationException();
        }
    }
}

最后如何运行此代码:

List<Student> students = hz.getList(listName);
addStudents(students);
StudentSearch search = new StudentSearch(hz);
Student result = search
    .findFirstByNameAndNumber(listName, "Tony", "001");
System.out.println(result);

我希望这有点帮助:)

答案 1 :(得分:0)

我无法获取对象中的id是什么,因为您需要查询id + name(因此id不是唯一的?)。如果您知道需要查询它们,请将它们存储在Set中(请提供更多信息)。

正如您所指出的,Set中没有谓词。恕我直言,这是因为无法将与Key无关的条目编入索引。如果没有可能添加索引(或者在密钥范围内扫描),谓词的概念就会崩溃,因为任何查询仍然会遍历整个集合。据我所知,你没有太多选择:

如果您使用套装必须有唯一条目,请不要

在这种情况下,请将其移至地图,将密钥用作任何人,例如您的对象 id 。如果可能有id,duplicates,你可以创建更复杂的键,如id + name,甚至哈希整个对象。一旦你必须放置一个新的对象,然后检查它是否已经存在,如果这样,你的自定义逻辑就会回落。 Map将为您提供所需的所有索引和谓词。

另一方面,如果由于某些不受你控制的原因,你必须使用套装...那么你可以通过多种方式做到这一点,但我会建议如下:

  1. 收听对Set的任何修改(或者如果是静态或一致性不是问题,请定期扫描该集

  2. 构建自定义索引

  3. 如何构建索引:

    这实际上取决于您想要的性能,您可以接受的RAM影响以及不同的查询方式。 (假设您只有查询总是相同的,例如&#34;名称等于&#34;)。

    MultiMap<String, String> index
    // index.put(name, key)
    

    通过添加,删除每个Set修改的条目来构建索引,在MultiMap中使用object.name作为键,并在multimap中将Set as值作为实际键。一旦您搜索了一个名称,您只需执行以下操作(伪伪代码)

    MultiMap<String, String> index;
    Map<String, your_object_class> your_set;
    
    function getByName(String name)
    {
      List<String> name_key_set index.get( name );
      List<your_object_class> out;
      for(String key : name_key_set)
        out.add(index.get(key));
      return out;
    }
    

    IMO没有什么可以调用Set上的查询(将查询称为检索数据的聪明方式而不是强力迭代),因为任何此类系统都需要 key =&gt; value < / strong>条目。

    有了更多信息,我们可以更好地帮助您:)