2016-12-29 36 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 =>值條目。

隨着進一步的信息,我們可以幫助您更好地:)

相關問題