【问题标题】:find an entry in hazelcast list quickly快速在 hazelcast 列表中找到一个条目
【发布时间】:2017-01-01 16:34:07
【问题描述】:

我有一个hazelcast Ilist,学生类包含5个属性,如(id,name,address,number,school)。现在列表中有10k条记录,我怎样才能找到名字是tony和number是的学生001很快除了for循环。我知道如果它是Imap我可以使用谓词过滤,但它是一个列表,我没有找到Ilist的谓词。任何帮助,非常感谢。

【问题讨论】:

    标签: list hazelcast predicate


    【解决方案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);
    

    我希望这会有所帮助:)

    【讨论】:

    • 很好的例子@noctarius。这应该转到 SO 文档。
    【解决方案2】:

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

    正如您指出的那样,Set 中没有谓词。恕我直言,这是因为无法索引与 Key 无关的条目。如果无法添加索引(或至少对键进行范围扫描),谓词的概念就会崩溃,因为任何查询仍将遍历整个集合。据我所知,您没有太多选择:

    如果您使用 set must to have unique entries,请不要!

    在这种情况下,将其移动到地图上,并像任何人一样使用键,例如您的对象 id。如果可能存在 id、重复项,您可以制作更复杂的键,例如 id+name 甚至散列整个对象。一旦您必须放置一个新对象,请创建密钥并检查它是否已经存在,如果如此,则使用您的自定义逻辑进行回退。 Map 会为您提供您想要的所有索引和谓词。

    另一方面,如果由于某些不受您控制的原因,您必须使用 set...,那么您可以通过多种方式进行操作,但我建议如下:

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

    2. 构建您的自定义索引

    如何建立索引:

    这实际上取决于您想要的性能、您可以接受的 RAM 影响以及查询的不同程度。 (假设您只有查询总是相同的,例如“名称等于”)。

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

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

    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 上调用 query(将 query 称为检索数据的聪明方法,而不是暴力迭代),因为任何此类系统都需要 key=>value 条目。

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

    【讨论】:

      猜你喜欢
      • 2014-07-15
      • 2015-05-13
      • 1970-01-01
      • 1970-01-01
      • 2022-11-17
      • 2016-03-17
      • 1970-01-01
      • 2019-05-28
      • 2010-11-14
      相关资源
      最近更新 更多