Indeksy prawie jak w bazie danych
Spotkałem się ostatnio z ciekawym problemem dotyczącym wyszukiwania danych. Zlecenie na program zaliczeniowy było proste napisać bibliotekę, ale bez użycia RDBMS. zabawa opiera się więc o kolekcje i ich odpowiednie projektowanie. Zadanie stosunkowo proste do momentu, w którym nie trzeba wyszukiwać danych po którejś z „kolumn”. W tym momencie mamy dwie drogi.
- Ręczne iterowanie się po kolekcji i wyszukiwanie po id przez porównanie z każdym obiektem.
- Emulowanie indeksu z RDBMS
Pierwsza metoda jest mało wydajna. Ma złożoność liniową, a przecież da się szybciej. Poza tym drugie rozwiązanie jest znacznie ciekawsze.
Krok 1. Klasa Autor
public class Author {<br></br> private int id;<br></br> private String name;<br></br><br></br> public String getName() {<br></br> return name;<br></br> }<br></br><br></br> public void setName(String name) {<br></br> this.name = name;<br></br> }<br></br><br></br> public int getId() {<br></br> return id;<br></br> }<br></br><br></br> public Author(int id, String name) {<br></br> super();<br></br> this.id = id;<br></br> this.name = name;<br></br> }<br></br><br></br>}
Krok 2. Po czym indeksujemy
Załóżmy, że chcemy indeksować po polu name. W sumie indeks dobry jak każdy inny.
Krok 3. „Tabela” authors
Zdefiniujmy klasę która będzie emulowała tabelę authors:
public class Authors extends LinkedList<author> {<br></br><br></br> private static final long serialVersionUID = 1L;<br></br>}</author>
Nie bawimy się w jakieś rozczulania czy kombinowanie tylko rozszerzamy LinkedList. W ten sposób mamy do dyspozycji odpowiednie metody i za darmo kontrolę typu.
Krok 4. „Indeks” na tabeli authors z pola name
Tu też nie ma się co bawić i rozczulać:
public class AuthorsNameIndex extends HashMap<string author="">{<br></br><br></br> private static final long serialVersionUID = 1L;<br></br><br></br>}</string>
I tu pierwsza pułapka. Pojawia man się poważna redundancja danych. Tabela authors i indeks przechowują wszystkich autorów. Nie jest to dobre rozwiązanie. Jednak nie będę go zmieniał ponieważ oznaczałoby to zmianę klasy Authors i w konsekwencji Author. Zmiana ta polegała by na ekstrakcji pola id jako klucza do map. Na razie olać.
Pytanie 1. Co robi programista?
Mamy już „Bazę danych”, która ma nawet „Indeks” w czym zatem problem? Przyjrzymy się takiemu oto kodowi:
Authors authors = new Authors();<br></br>authors.add(new Author(0, "a"));<br></br>authors.add(new Author(1, "b"));<br></br>
Widać w czym problem? Dla mało spostrzegawczych nie ma możliwości dodawania autorów do indeksu tak by obiekt dodany do tabeli i obiekt dodany do indeksu był to ten sam obiekt. Musimy zatem nadpisać metodę add() dla klasy Authors.
Nowa klasa wygląda tak:
public class Authors extends LinkedList<author> {<br></br><br></br> private static final long serialVersionUID = 1L;<br></br><br></br> private static AuthorsNameIndex authorsNameIndex = new AuthorsNameIndex();<br></br><br></br> @Override<br></br> public boolean add(Author o) {<br></br> boolean b = super.add(o);<br></br> authorsNameIndex.put(o.getName(), o);<br></br> return b;<br></br> }<br></br><br></br> public Author get(String name) {<br></br> return authorsNameIndex.get(name);<br></br> }<br></br><br></br>}</author>
Klasa została wzbogacona o indeks i metodę wybierającą na podstawie danych z indeksu.
Teraz wystarczy napisać testy i bangla 🙂