代码之家  ›  专栏  ›  技术社区  ›  stian

如何查询Java中的对象集合(标准/SQLlike)?

  •  29
  • stian  · 技术社区  · 17 年前

    假设您有几百个内存中对象的集合,并且需要查询此列表以返回与某些SQL或条件(如查询)匹配的对象。例如,您可能有一个汽车对象列表,并且您希望返回20世纪60年代生产的所有汽车,车牌以az开头,按车型名称排序。

    我知道 JoSQL ,是否有人使用过此功能,或有其他/本土解决方案的经验?

    7 回复  |  直到 17 年前
        1
  •  12
  •   Eric Weilnau    17 年前

    我已经用过 Apache Commons JXPath 在生产应用程序中。它允许您将XPath表达式应用于Java中的对象图。

        2
  •  24
  •   npgall    10 年前

    过滤是实现这一点的一种方法,如其他答案中所讨论的。

    不过,过滤是不可扩展的。表面上,时间的复杂性似乎是( n )(也就是说,如果集合中的对象数量将增加,则已经不可扩展),但实际上是因为 或更多 测试需要根据查询应用到每个对象,时间复杂度更准确地说是( NT 何处 T 是要应用于每个对象的测试数。

    因此,随着其他对象添加到集合中,性能将降低, 和/或 随着查询中测试数的增加。

    有另一种方法可以做到这一点,使用索引和集合理论。

    一种方法是 建造 指标 领域 在存储在集合中的对象中,随后将在查询中测试这些对象。

    假设你收集了 Car 对象和每个 小型车 对象有字段 color . 假设您的查询等同于“ SELECT * FROM cars WHERE Car.color = 'blue' “。你可以在上面建立一个索引 Car.color ,基本上是这样的:

    'blue' -> {Car{name=blue_car_1, color='blue'}, Car{name=blue_car_2, color='blue'}}
    'red'  -> {Car{name=red_car_1, color='red'}, Car{name=red_car_2, color='red'}}
    

    然后给出一个查询 WHERE Car.color = 'blue' 一套蓝色的汽车可以在( )时间复杂性。如果您的查询中有其他测试,那么您可以测试其中的每辆车。 候选集 检查它是否与查询中的其余测试匹配。由于候选集可能明显小于整个集合,因此时间复杂性为 小于 O( n )(在工程意义上,见下文评论)。性能不会降低 同样多 将其他对象添加到集合时。但这仍然不完美,继续读下去。

    另一种方法,我称之为 常设查询索引 .解释:使用常规的迭代和过滤,将迭代集合,并测试每个对象,以查看它是否与查询匹配。所以过滤就像在集合上运行查询。另一种方法是建立一个查询索引,在这个索引中,集合将在查询上运行,但对于集合中的每个对象只运行一次,即使可以多次查询集合。

    常设查询索引 希望用某种类型的 智能收藏 ,例如,当对象添加到集合中并从集合中移除时,集合将根据已向其注册的所有持续查询自动测试每个对象。如果一个对象与一个常设查询匹配,那么集合可以将其添加/删除到专用于存储与该查询匹配的对象的集合中。随后,可以在O中检索与任何已注册查询匹配的对象。( )时间复杂性。

    以上信息摘自 CQEngine (Collection Query Engine) .这基本上是一个NoSQL查询引擎,用于使用SQL类查询从Java集合中检索对象,而不必重复迭代集合的开销。它是建立在上述想法的基础上,再加上一些。免责声明:我是作者。它是开源的,在Maven Central中。 如果你觉得有帮助,请把这个答案投赞成票!

        3
  •  5
  •   Federico Piazza    12 年前

    是的,我知道这是一篇老文章,但是技术每天都会出现,答案会随着时间的推移而改变。

    我认为这是一个很好的问题来解决兰姆达吉。你可以在这里找到它: http://code.google.com/p/lambdaj/

    这里有一个例子:

    寻找活跃客户//(ITerable版本)

    List<Customer> activeCustomers = new ArrayList<Customer>();  
    for (Customer customer : customers) {  
      if (customer.isActive()) {  
        activeCusomers.add(customer);  
      }  
    }  
    

    LambdaJ版本

    List<Customer> activeCustomers = select(customers, 
                                            having(on(Customer.class).isActive()));  
    

    当然,在表演中有这种美的影响(有点…平均2次),但您能找到更可读的代码吗?

    它有许多特性,另一个例子是排序:

    排序迭代

    List<Person> sortedByAgePersons = new ArrayList<Person>(persons);
    Collections.sort(sortedByAgePersons, new Comparator<Person>() {
            public int compare(Person p1, Person p2) {
               return Integer.valueOf(p1.getAge()).compareTo(p2.getAge());
            }
    }); 
    

    用lambda排序

    List<Person> sortedByAgePersons = sort(persons, on(Person.class).getAge()); 
    
        4
  •  3
  •   joev    17 年前

    继续 Comparator 主题,你也可以看看 Google Collections 应用程序编程接口。特别是,它们有一个名为 Predicate ,其作用类似于 比较器 ,因为它是一个简单的接口,可以被过滤方法使用,比如 Sets.filter . 它们包括一大堆复合谓词实现、to do and、or等。

    根据数据集的大小,使用这种方法可能比使用SQL或外部关系数据库方法更有意义。

        5
  •  2
  •   Steve Moyer    17 年前

    如果需要一个具体的匹配,可以让类实现Comparator,然后创建一个包含所有哈希字段的独立对象,并使用它返回匹配的索引。当您想要在集合中找到多个(可能的)对象时,您必须求助于像josql这样的库(在我使用它的小情况下,它工作得很好)。

    一般来说,我倾向于将Derby嵌入到我的小应用程序中,使用Hibernate注释来定义我的模型类,并让Hibernate处理缓存方案来保持一切的快速。

        6
  •  1
  •   Bill the Lizard    17 年前

    我将使用一个比较器,以一系列年和车牌模式作为输入参数。然后只需遍历集合并复制匹配的对象。使用这种方法,您可能最终会得到一整套定制比较器。

        7
  •  0
  •   Yuval    17 年前

    这个 Comparator 选项并不坏,尤其是如果使用匿名类(以便不会在项目中创建多余的类),但最终当您查看比较流时,它与循环整个集合非常相似,它精确地指定匹配项的条件:

    if (Car car : cars) {
        if (1959 < car.getYear() && 1970 > car.getYear() &&
                car.getLicense().startsWith("AZ")) {
            result.add(car);
        }
    }
    

    然后是排序…那可能是背后的痛苦,但幸运的是有班 Collections 及其 sort 方法,其中一个方法接收 比较器