Domanda

Supponiamo di avere una raccolta di alcune centinaia di oggetti in memoria e di dover eseguire una query su questo elenco per restituire oggetti che corrispondono ad alcune query SQL o criteri.Ad esempio, potresti avere un Elenco di oggetti Auto e desideri restituire tutte le auto prodotte negli anni '60, con una targa che inizia con AZ, ordinate in base al nome del modello di auto.

Lo so JoSQL, qualcuno lo ha usato o ha esperienza con altre soluzioni/homegrown?

È stato utile?

Soluzione

ho usato Apache CommonsJXPath in un'applicazione di produzione.Ti consente di applicare espressioni XPath ai grafici di oggetti in Java.

Altri suggerimenti

Il filtraggio è un modo per farlo, come discusso in altre risposte.

Il filtraggio però non è scalabile.A prima vista la complessità temporale sembrerebbe essere O(N) (cioè.già non scalabile se il numero di oggetti nella collezione crescerà), ma in realtà perché uno o più i test devono essere applicati a ciascun oggetto a seconda della query, la complessità temporale più accuratamente è O(non) Dove T è il numero di test da applicare a ciascun oggetto.

Pertanto le prestazioni peggioreranno man mano che vengono aggiunti ulteriori oggetti alla raccolta, e/o all'aumentare del numero di test nella query.

Esiste un altro modo per farlo, utilizzando l'indicizzazione e la teoria degli insiemi.

Un approccio è quello di costruire indici sul campi all'interno degli oggetti archiviati nella tua collezione e che successivamente testerai nella tua query.

Supponiamo che tu abbia una collezione di Car oggetti e ogni Car l'oggetto ha un campo color.Supponiamo che la tua query sia l'equivalente di "SELECT * FROM cars WHERE Car.color = 'blue'".Potresti costruire un indice su Car.color, che sostanzialmente sarebbe simile a questo:

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

Quindi data una domanda WHERE Car.color = 'blue', l'insieme delle auto blu potrebbe essere recuperato in O(1) complessità temporale.Se nella tua query fossero presenti ulteriori test, potresti testare ciascuna vettura in essa contenuta insieme dei candidati per verificare se corrispondeva ai test rimanenti nella tua query.Poiché è probabile che l'insieme dei candidati sia significativamente più piccolo dell'intera raccolta, la complessità temporale lo è meno di O(N) (in senso ingegneristico, vedere i commenti sotto).Le prestazioni non peggiorano altrettanto, quando vengono aggiunti ulteriori oggetti alla raccolta.Ma questo non è ancora perfetto, continua a leggere.

Un altro approccio è quello che definirei a indice delle query permanenti.Spiegare:con l'iterazione e il filtraggio convenzionali, la raccolta viene ripetuta e ogni oggetto viene testato per verificare se corrisponde alla query.Quindi filtrare è come eseguire una query su una raccolta.Un indice di query permanente sarebbe il contrario, dove la raccolta viene invece eseguita sulla query, ma solo una volta per ogni oggetto nella raccolta, anche se la raccolta potrebbe essere interrogata un numero qualsiasi di volte.

UN indice delle query permanenti sarebbe come registrare una query con una sorta di raccolta intelligente, in modo tale che quando gli oggetti vengono aggiunti e rimossi dalla raccolta, la raccolta testerà automaticamente ciascun oggetto rispetto a tutte le query permanenti che sono state registrate con esso.Se un oggetto corrisponde a una query permanente, la raccolta potrebbe aggiungerlo/rimuoverlo a/da un set dedicato alla memorizzazione di oggetti corrispondenti a quella query.Successivamente, gli oggetti che corrispondono a una qualsiasi delle query registrate potrebbero essere recuperati in O(1) complessità temporale.

Le informazioni di cui sopra sono tratte da CQEngine (motore di query di raccolta).Si tratta fondamentalmente di un motore di query NoSQL per recuperare oggetti da raccolte Java utilizzando query di tipo SQL, senza il sovraccarico dell'iterazione della raccolta.È costruito attorno alle idee di cui sopra, più alcune altre.Disclaimer:Io sono l'autore.È open source e in Maven Central. Se lo trovi utile, vota questa risposta!

sì, lo so, è un vecchio post, ma le tecnologie compaiono ogni giorno e la risposta cambierà nel tempo.

Penso che questo sia un buon problema da risolvere con LambdaJ.Potete trovare qui:http://code.google.com/p/lambdaj/

Ecco un esempio:

CERCA CLIENTI ATTIVI // (Versione Iterable)

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

Versione LambdaJ

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

Naturalmente, avere questo tipo di bellezza ha un impatto sulla performance (un po'...in media 2 volte), ma riesci a trovare un codice più leggibile?

Ha molte molte funzionalità, un altro esempio potrebbe essere l'ordinamento:

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

Ordina con lambda

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

Continuando il Comparator tema, potresti anche voler dare un'occhiata al file Raccolte Google API.In particolare, hanno un'interfaccia chiamata Predicato, che svolge un ruolo simile a Comparator, in quanto è un'interfaccia semplice che può essere utilizzata con un metodo di filtraggio, come Imposta.filtro.Includono tutta una serie di implementazioni di predicati compositi, per eseguire AND, OR, ecc.

A seconda delle dimensioni del set di dati, potrebbe essere più sensato utilizzare questo approccio rispetto a un approccio SQL o a un database relazionale esterno.

Se hai bisogno di una singola corrispondenza concreta, puoi fare in modo che la classe implementi Comparator, quindi crei un oggetto autonomo con tutti i campi con hash inclusi e utilizzarlo per restituire l'indice della corrispondenza.Quando vuoi trovare più di un oggetto (potenzialmente) nella collezione, dovrai rivolgerti a una libreria come JoSQL (che ha funzionato bene nei casi banali per cui l'ho usata).

In generale, tendo a incorporare Derby anche nelle mie piccole applicazioni, utilizzo le annotazioni di Hibernate per definire le classi del mio modello e lascio che Hibernate si occupi degli schemi di memorizzazione nella cache per mantenere tutto veloce.

Vorrei utilizzare un comparatore che accetta un intervallo di anni e il modello di targa come parametri di input.Quindi scorri semplicemente la tua raccolta e copia gli oggetti corrispondenti.Probabilmente finirai per creare un intero pacchetto di comparatori personalizzati con questo approccio.

IL Comparator non è male, soprattutto se usi classi anonime (per non creare classi ridondanti nel progetto), ma alla fine quando guardi il flusso dei confronti, è praticamente come scorrere tu stesso l'intera raccolta, specificando esattamente il condizioni per abbinare gli articoli:

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

Poi c'è l'ordinamento...potrebbe essere una seccatura, ma per fortuna c'è classe Collections e il suo sort metodi, uno dei quali riceve a Comparator...

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top