Pergunta

Suponha que você tenha uma coleção de algumas centenas de objetos em memória e você precisa consultar esta lista para retornar objetos combinando alguns SQL ou critérios como consulta. Por exemplo, você pode ter uma lista de objetos de carro e você deseja retornar todos os carros feitos na década de 1960, com uma placa de licença que começa com AZ, ordenada pelo nome do modelo do carro.

Eu sei sobre JoSQL , ninguém tem usado isso, ou tem alguma experiência com outros / homegrown soluções?

Foi útil?

Solução

Eu tenho usado Apache Commons JXPath em um aplicativo de produção. Ele permite que você aplique expressões XPath para gráficos de objetos em Java.

Outras dicas

A filtragem é uma maneira de fazer isso, como discutido em outras respostas.

A filtragem não é, porém escalável. Na superfície complexidade de tempo parece ser O ( n ) (ou seja, já não escalável se o número de objetos na coleção vai crescer), mas, na verdade, porque um ou mais testes precisam de ser aplicado a cada objecto, dependendo da consulta, a complexidade do tempo é mais exacta o ( nt ) onde t é o número de testes para aplicar a cada objecto.

desempenho Então irá degradar como objetos adicionais são adicionados à coleção, e / ou como o número de testes na consulta aumenta.

Há uma outra maneira de fazer isso, usando a teoria de indexação e set.

Uma abordagem é construção índices em campos dentro dos objetos armazenados em sua coleção e que você vai posteriormente teste em sua consulta.

Digamos que você tenha uma coleção de objetos Car e cada objeto Car tem uma color campo. Diga a sua consulta é o equivalente a "SELECT * FROM cars WHERE Car.color = 'blue'". Você poderia construir um índice em Car.color, que seria basicamente parecido com este:

'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'}}

Em seguida, dado um WHERE Car.color = 'blue' consulta, o conjunto de carros azuis poderia ser recuperado em O ( 1 ) tempo de complexidade. Se houvesse testes adicionais em sua consulta, você poderia, então, testar cada carro em que set candidato para verificar se ele corresponde aos testes restantes em sua consulta. Uma vez que o conjunto de candidatos é susceptível de ser significativamente menor do que toda a coleção, complexidade de tempo é menos de O ( n ) (no sentido de engenharia, ver os comentários abaixo). Desempenho não degrada tanto , quando os objetos são adicionados à coleção. Mas isso ainda não é perfeito, a ler.

Outra abordagem, é o que eu chamo de um índice de consulta de pé . Para explicar: com iteração convencional e filtragem, a coleção é iterativo e cada objeto é testado para ver se ele corresponde a consulta. Assim, a filtragem é como correr uma consulta sobre uma coleção. Um índice de consulta em pé seria o contrário, onde a coleção em vez disso é atropelado a consulta, mas apenas uma vez para cada objeto na coleção, embora a coleção pode ser consultado qualquer número de vezes.

A índice de consulta de pé seria como registrar uma consulta com algum tipo de coleção inteligente , de modo que como objetos são adicionados e removidos da coleção, a coleção seria automaticamente testar cada objeto contra todas as consultas permanentes que tenham sido registadas com ele. Se um objeto corresponde a uma consulta de pé, em seguida, a coleção pode adicionar / removê-lo para / de um conjunto dedicado a objetos de armazenamento correspondentes essa consulta. Posteriormente, objetos correspondentes qualquer uma das consultas registrados poderia ser recuperado em O ( 1 ) complexidade de tempo.

A informação acima foi tirado do CQEngine (Coleção consulta Engine) . Isso basicamente é um mecanismo de consulta NoSQL para recuperar objetos de coleções Java usando SQL-como consultas, sem a sobrecarga de iteração através da coleção. Ele é construído em torno das idéias acima, além de um pouco mais. Disclaimer: Eu sou o autor. É open source e em maven central. Se você achar que é útil, por favor upvote esta resposta!

Sim, eu sei que é um post antigo, mas as tecnologias aparecem todos os dias e a resposta irá mudar no tempo.

Eu acho que este é um bom problema para resolvê-lo com LambdaJ. Você pode encontrá-lo aqui: http://code.google.com/p/lambdaj/

Aqui você tem um exemplo:

O OLHAR PARA CLIENTES ATIVOS // (versão Iterable)

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

versão LambdaJ

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

É claro que ter este tipo de impactos de beleza no desempenho (um pouco ... uma média de 2 vezes), mas você pode encontrar um código mais legível?

Ele tem muitos recursos, um outro exemplo poderia ser a classificação:

Classificar iterativo

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

Classificar com lambda

List<Person> sortedByAgePersons = sort(persons, on(Person.class).getAge()); 

Continuando o tema Comparator, você também pode querer dar uma olhada nas Google Collections API. Em particular, eles têm uma interface chamada predicado, que serve uma função semelhante à Comparator, na medida em que é uma interface simples que pode ser utilizado por um método de filtragem, como Sets.filter . Eles incluem um monte de implementações de predicados compostos, para fazer ANDs, ORs, etc.

Dependendo do tamanho do seu conjunto de dados, pode fazer mais sentido usar essa abordagem do que uma abordagem banco de dados relacional SQL ou externo.

Se você precisa de um único jogo de concreto, você pode ter a classe implementar Comparador, em seguida, criar um objeto autônomo com todos os campos hash incluídos e usá-lo para retornar o índice do jogo. Quando você quer encontrar mais de um objeto (potencialmente) na coleção, você vai ter que recorrer a uma biblioteca como JoSQL (que tem funcionado bem nos casos triviais Eu usei-o para).

Em geral, eu tendem a Derby inserir em até meus pequenos aplicativos, usar anotações do Hibernate para definir minhas classes de modelo e deixe negócio Hibernate com cache de esquemas para manter tudo rápido.

Gostaria de usar um comparador que leva uma série de anos e padrão de placa de licença como parâmetros de entrada. Em seguida, basta iterate através de sua coleção e copiar os objetos que jogo. Você provavelmente acabam fazendo um pacote inteiro de comparadores personalizados com esta abordagem.

A opção Comparator não é ruim, especialmente se você usar classes anônimas (de modo a não criar classes redundantes no projeto), mas, eventualmente, quando você olha para o fluxo de comparações, é praticamente apenas como looping sobre toda a coleção mesmo, especificando exactamente as condições para artigos de harmonização:

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

Depois, há a separação ... que poderia ser uma dor na parte traseira, mas felizmente há classe Collections e seus métodos sort, um dos quais recebe um Comparator ...

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top