2016-12-29 33 views
1

我有一个榛树Ilist,学生类包含5个属性,如(ID,姓名,地址,号码,学校)。现在列表中有10K条记录,我怎么能找到学生除了for循环之外,我的名字是tony,编号是001。我知道它是否是Imap我可以使用谓词来过滤,但它是一个列表,我没有找到Ilist的谓词。任何帮助,都非常感谢。快速在榛树列表中找到一个条目

回答

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); 

我希望这有助于一点:)

+0

很好的例子@noctarius。这应该转到SO文档。 –

0

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

正如您所指出的,Set中没有谓词。恕我直言,这是因为没有与密钥关联的条目不能被索引。没有可能性来索引索引(或者在leas范围内扫描关键字),谓词的概念就会崩溃,因为任何查询都会遍历整个集合。据我所知,你没有太多的选择:

如果你使用set必须有唯一的条目,不要!

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

从另一方面,如果由于某种原因不在你的控制之下,必须使用一套......那么你可以做它在很多方面,但我会建议如下:

  1. 听任何修改设置(或者,如果是静态或稠度不关心定期扫描设置

  2. 构建您的自定义索引

如何构建索引:

它确实取决于您想要的性能,可以接受的内存影响以及不同的查询可能会如何。(假设你只有查询总是相同的,例如“name等于”)。

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

可通过添加,每个集合修改删除条目,使用您的多重映射的object.name如SET键,实际密钥,这在多重映射价值结构索引。当你搜索一个给你只需做如下(伪伪代码)

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没有什么可以调用的一个集查询(指查询作为一个聪明的方法来检索数据而不是蛮力迭代),因为任何这样的系统将要求key =>值条目。

随着进一步的信息,我们可以帮助您更好地:)

相关问题