Welcome Guest Search | Active Topics | Members | Log In

LINQ dla języka Java Options · View
Emil
Posted: Friday, February 26, 2010 10:00:28 PM

Rank: Advanced Member

Joined: 10/29/2006
Posts: 50
Points: 147
Location: Warszawa, Polska
Obecnie w ramach porównania możliwości mojego rozwiązania do LINQ przygotowuję odpowiedniki zapytań ze strony 101 LINQ Samples. Niestety, mam problem z zapytaniem potrójnie pogrupowanym.
Czy ktoś z Państwa mógłby mi podpowiedzieć, jak to ugryźć?
Wygląda ono następująco:
Quote:
This sample uses group by to partition a list of each customer's orders, first by year, and then by month.

Code:
public void Linq43()
{
    List<Customer> customers = GetCustomerList();

    var customerOrderGroups =
        from c in customers
        select
            new
            {
                c.CompanyName,
                YearGroups =
                    from o in c.Orders
                    group o by o.OrderDate.Year into yg
                    select
                        new
                        {
                            Year = yg.Key,
                            MonthGroups =
                                from o in yg
                                group o by o.OrderDate.Month into mg
                                select new { Month = mg.Key, Orders = mg }
                        }
            };

    ObjectDumper.Write(customerOrderGroups, 3);
}


Udało mi się stworzyć coś, co daje tylko nieco zbliżony wynik, tj na ostatnim poziomie grupuje poprawnie, ale na wyższych już nie:
Code:

List<Customer> customers = getCustomerList()
List<Map<String, Object>> customerOrderGroups = #{
    (unique(customers.companyName) as cn).
    (cn as cn, (customers where companyName == cn).orders group as cnOrders).(
        (unique(cnOrders.orderDate.getYear()) as oYear).
        (cn as cn, oYear as oYear, ((cnOrders where orderDate.getYear() == oYear) group as yOrders)).(
                (unique(yOrders.orderDate.getMonth()) as oMonth).
                (cn as companyName, (oYear as year, (oMonth as month, (yOrders where orderDate.getMonth() == oMonth) group as orders) group as monthGroups) group as yearGroups)                        
        )
    )
    
};


Schemat danych jest następujący:
Code:
public class Product {
    public int productID;
    public String productName;
    public String category;
    public double unitPrice;
    public int unitsInStock;
}

public class Order {
    public int orderID;
    public Date orderDate;
    public double total;
}

public class Customer {
    public String customerID;
    public String companyName;
    public String address;
    public String city;
    public String region;
    public String postalCode;
    public String country;
    public String phone;
    public String fax;
    public List<Order> orders;
}

Z góry dziękuję za pomoc.
subieta
Posted: Saturday, February 27, 2010 11:42:23 AM

Rank: Advanced Member

Joined: 12/22/2004
Posts: 675
Points: 704
Location: Legionowo
Na razie nie mogę zrozumieć schematu: Order nie jest powiązany z Product, metody zastosowane w zapytaniu nie są wyspecyfikowane. orderDate ma składniki Year oraz Month, czy tak?. Poniewaz nie znam zbyt dobrze LINQ, nie jestem pewien jaka ostatecznie struktura danych ma być rezultatem.
Czy chodzi o coś takiego:
Code:
bag(
  struct(
    cus as c,              // klient jako c
    compName as cn,        // nazwa firmy jako cn
    bag(                   // zamówienia zgrupowane wg lat nazwane yg
      struct(
        yea as y,          //unikalny rok dla danego klienta jako y
        bag(               // zamówienia w ramach danego roku zgrupowane wg miesiąca i nazwane mg
          struct(
            mon as m,      //unikalny miesiąc w ramach roku w ramach danego klienta jako m
            bag(ord) as o // grupa referencji do zamówień w ramach danego miesiąca, danego roku i dla danego klienta jako o
          )
        ) as mg
      )
    ) as yg
  )
)

W tej strukturze danych jest bag struktur trzyelementowych, pierwszy element jest nazwany c oznaczający referencję do customer, następnie nazwa firmy nazwana cn i następnie bag struktur nazwany yg grupujący według unikalnych lat. W tym bagu są struktury skladające sie z dwóch elementów: unikalnego roku, nazwanego y, oraz bagu miesiecy w ramach danego roku nazwanego mg. W ramach tej grupy mamy unikalny miesiąc nazwany m oraz grupę zamówien w danym miesiącu w danym roku nazwaną o.
Czy tak nalezy rozumieć wynik? Jezeli tak, to nie ma problemu ze sformułowaniem zapytania w SBQL.
Code:

Customers as c join c.companyName as cn join
(
  (                                 
    (
      (unique(c.orders.Orders.orderDate.Year ) as y
    ) join             
    (
      (c.orders.Orders where orderDate.Year = y) groupas yGroup
    )
  ). 
  (y as y,
    (
      (unique(yGroup.orderDate.Month) as m) join                 
      (yGroup where orderDate.Month = m) groupas o
    )               
    groupas mg
  )
) groupas yg

Załozyłem, że Customers jest kolekcją obiektów klasy Customer zaś Orders jest kolekcją obiektów klasy Order. Deklarację public List<Order> orders traktuję jako listę pointerów do Orders. yGroup pojawiła się jako pomocnicza grupa grupujaca orders wg lat. Nie jest wyspecyfikowana w wyniku, ale to zalezy od oczekiwanej końcowej struktury danych. Mam nadzieję, ze nie poplatałem nawiasów, bo z tym był główny problem. Można go obejść przez szersze zastosowanie pomocniczych nazw.

Jezeli nie jest to dobre rozwiązanie, to proszę o dokładniejsze zalozenie odnośnie zapytania, schematu struktury danych i oczekiwanego wyniku.
Emil
Posted: Saturday, February 27, 2010 12:57:28 PM

Rank: Advanced Member

Joined: 10/29/2006
Posts: 50
Points: 147
Location: Warszawa, Polska
Dziękuję za odpowiedź.

subieta wrote:
Na razie nie mogę zrozumieć schematu: Order nie jest powiązany z Product, metody zastosowane w zapytaniu nie są wyspecyfikowane. orderDate ma składniki Year oraz Month, czy tak?.

To prawda, Product nie ma zastosowania w tym zapytaniu, choć jest on używany w innych zapytaniach przykładowych LINQ.
Date jest reprezentacją javową daty, obiektem klasy java.util.Date, zawiera min. metody getYear() i getMonth() zwracające odpowiednio rok i miesiąc jako Integer. W moim rozwiązaniu można używać metod w zapytaniach, np. wynikiem zapytania date.getMonth() jest bag obiektów Integer.

subieta wrote:
Poniewaz nie znam zbyt dobrze LINQ, nie jestem pewien jaka ostatecznie struktura danych ma być rezultatem.
Czy chodzi o coś takiego:
Code:
bag(
  struct(
    cus as c,              // klient jako c
    compName as cn,        // nazwa firmy jako cn
    bag(                   // zamówienia zgrupowane wg lat nazwane yg
      struct(
        yea as y,          //unikalny rok dla danego klienta jako y
        bag(               // zamówienia w ramach danego roku zgrupowane wg miesiąca i nazwane mg
          struct(
            mon as m,      //unikalny miesiąc w ramach roku w ramach danego klienta jako m
            bag(ord) as o // grupa referencji do zamówień w ramach danego miesiąca, danego roku i dla danego klienta jako o
          )
        ) as mg
      )
    ) as yg
  )
)

Tak, z tą małą różnicą, że w pierwszej strukturze nie występuje obiekt c:
Code:
bag(
  struct(
    compName as companyName,        // nazwa firmy jako cn
    bag(                   // zamówienia zgrupowane wg lat nazwane yg
      struct(
        yea as year,          //unikalny rok dla danego klienta jako y
        bag(               // zamówienia w ramach danego roku zgrupowane wg miesiąca i nazwane mg
          struct(
            mon as month,      //unikalny miesiąc w ramach roku w ramach danego klienta jako m
            bag(ord) as orders // grupa referencji do zamówień w ramach danego miesiąca, danego roku i dla danego klienta jako o
          )
        ) as mg
      )
    ) as yg
  )
)



subieta wrote:
W tej strukturze danych jest bag struktur trzyelementowych, pierwszy element jest nazwany c oznaczający referencję do customer, następnie nazwa firmy nazwana cn i następnie bag struktur nazwany yg grupujący według unikalnych lat. W tym bagu są struktury skladające sie z dwóch elementów: unikalnego roku, nazwanego y, oraz bagu miesiecy w ramach danego roku nazwanego mg. W ramach tej grupy mamy unikalny miesiąc nazwany m oraz grupę zamówien w danym miesiącu w danym roku nazwaną o.
Czy tak nalezy rozumieć wynik? Jezeli tak, to nie ma problemu ze sformułowaniem zapytania w SBQL.
Code:

Customers as c join c.companyName as cn join
(
  (                                 
    (
      (unique(c.orders.Orders.orderDate.Year ) as y
    ) join             
    (
      (c.orders.Orders where orderDate.Year = y) groupas yGroup
    )
  ). 
  (y as y,
    (
      (unique(yGroup.orderDate.Month) as m) join                 
      (yGroup where orderDate.Month = m) groupas o
    )               
    groupas mg
  )
) groupas yg

Załozyłem, że Customers jest kolekcją obiektów klasy Customer zaś Orders jest kolekcją obiektów klasy Order. Deklarację public List<Order> orders traktuję jako listę pointerów do Orders. yGroup pojawiła się jako pomocnicza grupa grupujaca orders wg lat. Nie jest wyspecyfikowana w wyniku, ale to zalezy od oczekiwanej końcowej struktury danych. Mam nadzieję, ze nie poplatałem nawiasów, bo z tym był główny problem. Można go obejść przez szersze zastosowanie pomocniczych nazw.

Jezeli nie jest to dobre rozwiązanie, to proszę o dokładniejsze zalozenie odnośnie zapytania, schematu struktury danych i oczekiwanego wyniku.


Ostatecznie działające z uwzględnieniem powyższych poprawek wygląda tak:
Code:
List<Map<String, Object>> customerOrderGroups = #{
    (customers as c).
    (c.companyName as companyName join
      (                                 
        (
          (unique(c.orders.orderDate.getYear() ) as year
        ) join             
        (
          (c.orders where orderDate.getYear() == year) group as yearGroups
        )
      ).
      (year as year,
        (
          (unique(yearGroups.orderDate.getMonth()) as month) join                 
          (yearGroups where orderDate.getMonth() == month) group as orders
        )               
        group as monthGroups
      )
      group as yearGroups
    )
    )
};

Dziękuję za rozwiązanie. Nie wiem, czy potencjalnych użytkowników da się przekonać o większej łatwości takiego zapytania w porównaniu do zapytania LINQ, w każdym razie widać na tym przykładzie, że SBQL ma potencjał budowania skomplikowanych zapytań bez użycia dodatkowych operatorów typu group by.
subieta
Posted: Saturday, February 27, 2010 2:35:17 PM

Rank: Advanced Member

Joined: 12/22/2004
Posts: 675
Points: 704
Location: Legionowo
To zapytanie nie jest typowe dla SBQL i z tego powodu poziom jego skomplikowania jest podobny do zapytania w LINQ. Trudno twierdzić, że jest prostsze. Natomiast podobne zapytania mogą tworzyć problemy dla LINQ z dwóch powodów:

1. Optymalizacja: operator group by jest silnie uwarunkowany fizyczną implementacją, zatem jakiekolwiek metody polegające na przepisywaniu stają się wręcz karkołomne. Operator group as SBQL-a jest pod tym względem normalnym operatorem algebraicznym, ortogonalnym do innych, wiec nie implikuje specjalnych problemów dla optymalizacji.

2. Anomalie znane z SQL związane z pustymi grupami oraz (ewentualnie) wartościmi zerowymi. Chodzi o to, ze group by pomija pustą grupę, przez co niektore zapytania bez ostrzeżenia dostarczają zły wynik. Załóżmy, że ktoś chciałby na podstawie Customers obliczyć średnią liczbę pracowników w działach, grupując je po companyName. Jezeli tak by zrobiłby, to otrzymałby średnią, ale z działów zawierających co najmniej jednego pracowników. Dla pustych działów grupy nie będą tworzone. Zatem wynik bedzie zniekształcony. Niejaki Werner Kiessling w referacie na VLDB nazwał to "semantic reef". Nie wiem czy LINQ ma wartości zerowe, ale jezeli ma, to jest jeszcze jeden problem znany z SQL-a. Mianowicie, wartości zerowe utworzą jeszcze jedną grupę. Zatem jezeli dla niektórych Customers companyName będzie zawierało Null, to liczba działów będzie o 1 większa i próba obliczenia średniej liczby pracowników w działach znowu da błędny wynik. Tych problemów SBQL unika, dlatego nie ma w nim ani group by ani wartości zerowych.

Jezeli ktoś chciałby więcej porównania SBQL z LINQ to zapraszam na stronę http://www.sbql.pl/various/SBQL_LINQ%20query%20comparison.htm
LINQ nie ma oczywiście na razie możliwości zapytań rekurencyjnych, w odróżnieniu od SBQL, patrz http://www.sbql.pl/Topics/SBQL%20Recursive.html
Polecam banalne zapytanie E.TC.12, którego nie można zadać ani w SQL ani w LINQ.

Strona http://www.sbql.pl/various/SBQL_Examples_4_LINQ.cli.htm zawiera trudniejsze przykłady w SBQL, z których niektore mogą być bardzo trudne lub niemożliwe do sformulowania w LINQ. Wysłalem je do LINQowego guru z db4o z prośba o sformułowanie ich w LINQ, ale wyraźnie do dzisiaj rękawica nie została podjęta. Myślę, że człowiek próbował, ale nie za bardzo mu szło, więc się zniechęcił. Dyskusja zresztą jest już zamknięta, świat uznał, że LINQ jest the best i nic mu nie może zagrozić.
Emil
Posted: Saturday, February 27, 2010 3:33:04 PM

Rank: Advanced Member

Joined: 10/29/2006
Posts: 50
Points: 147
Location: Warszawa, Polska
Ciekawe przykłady, za pozwoleniem wykorzystam je do testów i promowania mojego rozwiązania.

Taka myśl mnie teraz naszła, jeżeli moglibyśmy dobrze określić algorytm pisania zapytań wielokrotnie pogrupowanych w SBQL, to chyba byłoby technicznie możliwe stworzenie makro-operatora o funkcjonalności zbliżonej do group by w LINQ.
Celem oczywiście byłaby przyjazność dla użytkownika.
Taki operator byłby tłumaczony na szereg "normalnych" zapytań, które mogły by być przepisane w fazie optymalizacji. Zakładając, w "normalnym" zapytaniu nie ma anomalii, nie powinno ich też być w zapytaniu wygenerowanym na podstawie makro-operatora.
subieta
Posted: Saturday, February 27, 2010 3:46:48 PM

Rank: Advanced Member

Joined: 12/22/2004
Posts: 675
Points: 704
Location: Legionowo
Emil wrote:
Ciekawe przykłady, za pozwoleniem wykorzystam je do testów i promowania mojego rozwiązania.

Taka myśl mnie teraz naszła, jeżeli moglibyśmy dobrze określić algorytm pisania zapytań wielokrotnie pogrupowanych w SBQL, to chyba byłoby technicznie możliwe stworzenie makro-operatora o funkcjonalności zbliżonej do group by w LINQ.
Celem oczywiście byłaby przyjazność dla użytkownika.
Taki operator byłby tłumaczony na szereg "normalnych" zapytań, które mogły by być przepisane w fazie optymalizacji. Zakładając, w "normalnym" zapytaniu nie ma anomalii, nie powinno ich też być w zapytaniu wygenerowanym na podstawie makro-operatora.


Oczywiście, przykłady są dostępne publicznie i każdy może je wykorzystać do dowolnych celów. Zrzekam sę nawet praw autorskich :).
Co do pomysłu na specjalny operator, czekam na propozycję. Operator group as z SBQLa pojawił się własnie dlatego, że razem z Markku Sakkinenem próbowaliśmy kiedyś uogólnić i sfomalizować semantykę operatora group by języka ODMG OQL. Po dwóch tygodniach zmagań doszliśmy do wniosku, że taki group by jest w językach obiektowych zbędny, bo można go łatwo zastąpić innymi operatorami nie powodujacymi ani raf, ani anomalii. Z całej dyskusji pozostał tylko operator group as, kóry oczywiście przydaje się w wielu innych kontekstach, nie tylko w kontekstach, ktore w innych językach wymagają group by. Ale chętnie zmienię poglądy jezeli zobaczę dobrą propozycję.
Emil
Posted: Monday, March 15, 2010 1:54:26 PM

Rank: Advanced Member

Joined: 10/29/2006
Posts: 50
Points: 147
Location: Warszawa, Polska
Czy ktoś z Państwa pracował nad tematem statycznego wiązania nazw w SBQL?
Myślę, że takie wiązanie miałoby spore korzyści, po pierwsze szybkość działania (w czasie wykonania nie jest potrzebny stos ENVS i funkcja bind), po drugie niezależność środowiska wykonania zapytania (np. możliwe jest wygenerowanie kodu zapytania w języku nie posiadającego dynamicznego wiązania nazw).
Obecnie pracuję nad tym w ramach mojego rozwiązania, pierwsze efekty są zachęcające. Udało mi się stworzyć emiter, który generuje kod Javy bez dynamicznego wiązania nazw. Różnica w wydajności jest kolosalna. W przypadku zapytania z grupowaniem zaproponowanego przez Profesora wynosi:
- 100 uruchomień w trybie interpretera z dynamicznym wiązaniem nazw przez refleksję: 22034 ms
- 100 uruchomień wygenerowanego kodu ze statycznym wiązaniem nazw: 306 ms

Rozwiązanie to pisałem nieco po omacku i nie mam pewności że zadziała ono dla wszystkich zapytań. Stąd moje pytanie o badania w tym zakresie.
subieta
Posted: Monday, March 15, 2010 8:58:54 PM

Rank: Advanced Member

Joined: 12/22/2004
Posts: 675
Points: 704
Location: Legionowo
Emil wrote:
Czy ktoś z Państwa pracował nad tematem statycznego wiązania nazw w SBQL?
Myślę, że takie wiązanie miałoby spore korzyści, po pierwsze szybkość działania (w czasie wykonania nie jest potrzebny stos ENVS i funkcja bind), po drugie niezależność środowiska wykonania zapytania (np. możliwe jest wygenerowanie kodu zapytania w języku nie posiadającego dynamicznego wiązania nazw).
Obecnie pracuję nad tym w ramach mojego rozwiązania, pierwsze efekty są zachęcające. Udało mi się stworzyć emiter, który generuje kod Javy bez dynamicznego wiązania nazw. Różnica w wydajności jest kolosalna. W przypadku zapytania z grupowaniem zaproponowanego przez Profesora wynosi:
- 100 uruchomień w trybie interpretera z dynamicznym wiązaniem nazw przez refleksję: 22034 ms
- 100 uruchomień wygenerowanego kodu ze statycznym wiązaniem nazw: 306 ms

Rozwiązanie to pisałem nieco po omacku i nie mam pewności że zadziała ono dla wszystkich zapytań. Stąd moje pytanie o badania w tym zakresie.

Moja deklarowana filozofia jest taka, że wiazania są dynamiczne, zaś można je zmienić na statyczne jako zabieg optymalizacyjny. Co do wiązań statycznych, nie będą działać dla bazy danych, ponieważ program można kompilować nawet w sytuacji, kiedy żadnej bazy danych nie ma, jest tylko jej schemat. Jezeli chodzi o wiązanie statyczne do zmiennych lokalnych procedur i ew. lokalnego środowiska aplikacji, z wiązaniami statycznymi też jest problem ze względu na kolekcje - nie mozemy zwrócić referencji do elementów kolekcji dopóki jej nie będzie. Podobnie z wartościami zerowymi, czyli kolekcjami z licznością [0..1]. Nawet w przypadku wiązań statycznych jakaś forma ENVS musi istnieć, ponieważ np. operatory niealgebraiczne i wywołania metod muszą go mieć w trakcie działania. Zresztą, jest on we wszystkich językach programowania. Natomiat często (np. w C) jest on silnie zredukowany, referencje do niego mają postać baza + offset, gdzie baza jest adresem podstawy ostatniej sekcji stosu, zaś offset jest przesunięciem wartości danego bytu programistycznego (np. zmiennej) w stosunku do bazy. Nazwę wiąże się więc do offsetu. Ten model także bardzo się kruszy w przypadku kolekcji, stringów i blobów o nieznanym rozmiarze, wartości zerowych i innych anomalii.

Sądzę, że główny zysk w podanym przykladzie nie wynika z zalet statycznego wiązania nazw, a z wad refleksji zrealizowanej w Java, o której się słyszy, ze jest bardzo wolna.
Emil
Posted: Tuesday, March 16, 2010 10:16:47 AM

Rank: Advanced Member

Joined: 10/29/2006
Posts: 50
Points: 147
Location: Warszawa, Polska
subieta wrote:
Moja deklarowana filozofia jest taka, że wiazania są dynamiczne, zaś można je zmienić na statyczne jako zabieg optymalizacyjny.

Nawet w przypadku wiązań statycznych jakaś forma ENVS musi istnieć, ponieważ np. operatory niealgebraiczne i wywołania metod muszą go mieć w trakcie działania. Zresztą, jest on we wszystkich językach programowania. Natomiat często (np. w C) jest on silnie zredukowany, referencje do niego mają postać baza + offset, gdzie baza jest adresem podstawy ostatniej sekcji stosu, zaś offset jest przesunięciem wartości danego bytu programistycznego (np. zmiennej) w stosunku do bazy. Nazwę wiąże się więc do offsetu. Ten model także bardzo się kruszy w przypadku kolekcji, stringów i blobów o nieznanym rozmiarze, wartości zerowych i innych anomalii.

Oczywiście, dynamiczne wiązanie nazw jest potrzebne w obiektowym języku programowania / zapytań. Oprócz powodów wymienionych przez Profesora również dlatego, że bez niego nie da się, lub jest znacznie trudniej zrealizować dziedziczenie i polimorfizm metod. Jednak w moim konkretnym rozwiązaniu zapytania uruchamiane są w maszynie wirtualnej Java, która posiada własny mechanizm stosów i dynamicznego wiązania nazw. Im więcej da się z niej "wycisnąć" pisząc bardziej optymalny kod, tym większa jest ogólna wydajność rozwiązania, stąd moje zainteresowanie statycznym wiązaniem nazw.

subieta wrote:
Co do wiązań statycznych, nie będą działać dla bazy danych, ponieważ program można kompilować nawet w sytuacji, kiedy żadnej bazy danych nie ma, jest tylko jej schemat. Jezeli chodzi o wiązanie statyczne do zmiennych lokalnych procedur i ew. lokalnego środowiska aplikacji, z wiązaniami statycznymi też jest problem ze względu na kolekcje - nie mozemy zwrócić referencji do elementów kolekcji dopóki jej nie będzie. Podobnie z wartościami zerowymi, czyli kolekcjami z licznością [0..1].

Nie do końca rozumiem, czemu to nie może działać w bazie danych. W moim rozwiązaniu wygenerowane zapytanie jest funkcją, która na wejściu przyjmuje dane do przetworzenia i zwraca wynik. Do jej generacji potrzebna jest informacja o typach przetwarzanych danych i oczywiście sam tekst zapytania. Jeżeli zakładamy, że w bazie definicje typów są rozdzielne od definicji danych, to można skompilować zapytanie bez samych danych.
Problemem który widzę z zastosowaniem mojego rozwiązania w bazach jest dynamiczna kompilacja zapytań, jak również przepisywanie zapytań już skompilowanych, np celem optymalizacji kosztowej. Choć nie wydaje się to problemem nie do rozwiązania, ponieważ Java oferuje możliwość ładowania nowych klas w trakcie działania programu (choć bez specjalnych środków nie umożliwia usuwania nieużywanych klas co potencjalnie może powodować wyciek pamięci).

subieta wrote:
Sądzę, że główny zysk w podanym przykladzie nie wynika z zalet statycznego wiązania nazw, a z wad refleksji zrealizowanej w Java, o której się słyszy, ze jest bardzo wolna.

Oczywiście, refleksja jest kosztowna, choć próbowałem również innych, bardziej zaawansowanych technik wiązania nazw z obiektów Java, z dynamicznym generowaniem bajtkodu włącznie. Mimo wszystko "czysty" wygenerowany kod Javowy daje najlepsze rezultaty.
subieta
Posted: Tuesday, March 16, 2010 11:30:06 AM

Rank: Advanced Member

Joined: 12/22/2004
Posts: 675
Points: 704
Location: Legionowo
Emil wrote:
Nie do końca rozumiem, czemu to nie może działać w bazie danych. W moim rozwiązaniu wygenerowane zapytanie jest funkcją, która na wejściu przyjmuje dane do przetworzenia i zwraca wynik. Do jej generacji potrzebna jest informacja o typach przetwarzanych danych i oczywiście sam tekst zapytania. Jeżeli zakładamy, że w bazie definicje typów są rozdzielne od definicji danych, to można skompilować zapytanie bez samych danych.


Skompilowac oczywiście można, ale w skompilowanym programie wiązania nazw bedą musiały być dynamiczne.

Statycznym wiązaniem nazywa sie sytuację, kiedy podczas kompilacji i linkowania programu nazwy bytów programistycznych są zamieniane na fizyczne adresy pamięci operacyjnej albo na offsety, które już ostatecznie zamienia się na adresy po tym, kiedy znana jest podstawa górnej sekcji stosu. W tym przypadku nie ma żadnych operacji na nazwach podczas czasu wykonania. Natomiast wiązanie dynamiczne oznacza, że nazwy bytów programistycznych są dostępne (często w postaci symbolicznej) podczas runtime, zaś nazwy w programie są podczas runtime zamieniane na te byty programistyczne na podstawie ich nazw.

Pomiędzy tymi dwoma skrajnościami istnieje mnóstwo przypadków pośrednich. W szczególności nazwy bytów programistycznych mogą być przechowywane jako kody w specjalnej tabeli, ktorej każdy wiersz zawiera także fizyczny lub symboliczny adres takiego bytu. Nazywa się ją "indirection table". W tym przypadku część wiązania jest statyczna, gdyż nazwy w programie są zamieniane na kody nazw i ostatecznie podczas kompilacji znajdowany jest odpowiedni wiersz indirection table dla kazdej nazwy. Natomiast druga kolumna indirection table jest zapełniana dynamicznie podczas czasu wykonania i ona ostatecznie ustala wiązanie. Tak działał np. system LOQIS, nie wiem jak jest w systemie ODRA.

Języki zapytań historycznie są oparte na wiązaniu dynamicznym. To w szczególności umożliwia wstawianie zapytań jako stringów do innych programów. Stringi te są martwe podczas kompilacji, ożywają dopiero podczas czasu wykonania i dopiero wtedy może być przeprowadzone wiązanie. Zintegrowany język, w którym zapytania pełnią rolę wyrażeń jezyka programowania (DBPL, LOQIS, C#+LINQ, ODRA) niewiele tę sytuację zmienia jeżeli przyjmiemy, ze baza danych nie jest własnością jednego programu i istnieje niezależnie od jakichkolwek programów. W takim układzie możliwe są jakieś operacje zmierzające do wiązania nazw podczas czasu kompilacji, ale ostateczne wiązanie musi być podczas runtime.
tkowals
Posted: Tuesday, March 16, 2010 12:27:16 PM
Rank: Advanced Member

Joined: 4/8/2006
Posts: 31
Points: 51
Location: PŁ
Quote:
Statycznym wiązaniem nazywa sie sytuację, kiedy podczas kompilacji i linkowania programu nazwy bytów programistycznych są zamieniane na fizyczne adresy pamięci operacyjnej albo na offsety, które już ostatecznie zamienia się na adresy po tym, kiedy znana jest podstawa górnej sekcji stosu.


Zastanawiam się nad następującą sytuacją. Weźmy np. zapytanie:
Code:
Person.age

Załóżmy, że implementacja składowania danych zapewnia, że:
- obiekty Person znajdują się w i-tym potomnym korzenia bazy $root obiekcie agregującym,
- a każdy podobiekt age jest j-tym potomkiem obiektu Person.
Wydaje mi się, że kompilator mógłby na podstawie analizy schematu stwierdzić, że nazwy bytów programistycznych nie są potrzebne do wykonania i mógłby wygenerować kod, który zwraca wynik zapytania odpowiednio odczytując obiekty z bazy danych.
Czy w przypadku takiej optymalizacji mamy sytuacje pośrednią między dynamicznym, a statycznym wiązaniem nazw?
Wydaje mi się, że ważne w tym kontekście jest przyjęcie modelu składowania danych, bo jeżeli statyczne wiązanie rozpatrujemy w kontekście płaskiego składu danych, w którym jedynym sposobem określenia pozycji zmiennej jest offset, to faktycznie w w/w przypadku wiązanie będzie dynamiczne.
Czy przyjęcie modelu na wyższym poziomie, w którym pozycje obiektu można określić względem adresu obiektu rodzica numerem węzła potomnego, a nie offsetem przesunięcia, nie pozwoliłoby nazwać w/w optymalizacje statycznym wiązaniem?
Emil
Posted: Tuesday, March 16, 2010 12:55:18 PM

Rank: Advanced Member

Joined: 10/29/2006
Posts: 50
Points: 147
Location: Warszawa, Polska
Faktycznie warto uściślić co nazywamy statycznym wiązaniem. Weźmy przykład zapytania z mojego rozwiązania:
Code:
        List<Customer> customers = getCustomerList();
        List<Customer> waCustomers = #{
            customers where region == "WA"
        };


Zapytanie to wygeneruje następującą klasę Javy:
Code:
public class LinqComparison_SbqlQuery3 extends PureJavaQuery {
    private java.util.List<pl.wcislo.sbql4j.javac.test.linq_comp.model.Customer> customers;

    public LinqComparison_SbqlQuery3(
        java.util.List<pl.wcislo.sbql4j.javac.test.linq_comp.model.Customer> customers) {
        this.customers = customers;
    }

    /** query='customers where region == "WA"'
    */
    public java.util.List<Customer> executeQuery() {
        java.util.List<Customer> _ident_customers = customers;
        java.util.List<Customer> _queryResult = new java.util.ArrayList<Customer>();
        int _whereLoopIndex = 0;
        for (Customer _whereNestedEl : _ident_customers) {
            String _ident_region = _whereNestedEl.region;
            String _literal_ = "WA";
            Boolean _equalsResult = OperatorUtils.equalsSafe(_ident_region, _literal_);
            if (_equalsResult) {
                _queryResult.add(_whereNestedEl);
            }
            _whereLoopIndex++;
        }
        return _queryResult;
    }
}


W tym przykładzie linijka
Code:
String _ident_region = _whereNestedEl.region;

stanowi wiązanie do nazwy "region", co normalnie wymagałoby najpierw wykonania nested na elemencie kolekcji "customers" i dynamicznego wiązania nazwy z obiektów zagnieżdżonych.
Z punktu widzenia semantyki języka zapytań w kodzie mamy wiązanie statyczne, bo _whereNestedEl.region wskazuje na konkretny obiekt.
Z punktu widzenia programu jako całości, jest to zamiana jednej nazwy na drugą, która jest rozwiązywana podczas ostatecznej kompilacji kompilatorem Java.
subieta
Posted: Tuesday, March 16, 2010 2:22:25 PM

Rank: Advanced Member

Joined: 12/22/2004
Posts: 675
Points: 704
Location: Legionowo
Moim zdaniem, optymalizacje są tylko poprawianiem czasu wykonania, natomiast różnica pomiędzy statycznym i dynamicznym wiązaniem ma charakter koncepcyjny. Przy statycznym wiązaniu nazwy bytów pogramistycznych w ogóle znikają zarówno ze składu (istnieją tylko w typie lub w klasie, które są drugiej kategorii programistycznej) jak i z kodu. Jezeli nazwy w jakiejkolwiek formie są wykorzystywane podczas runtime, to mamy do czynienia z wiązaniem dynamicznym. Wiązanie dynamiczne jest oczywiście znacznie bardziej elastyczne, chociaż implikuje jakies straty czasowe. Ale to moze podlegać licznym optymalizacjom. W LOQIS zrobilem tak, że każdy obiekt złożony miał na początku taki malutki indeks, który był wynikiem funkcji nested działajacej na tym obiekcie. To jest oczywiście element mechanizmu wiązania, który znacznie poprawił czas wykonania zapytań. Takich optymalizacji mogą być oczywiście tysiące. W szczególności, można byłoby rozpoznawać typy "offsetowe", t.j. takie, w których jest stały format dla wszystkich pól i wtedy optymalizować wiązanie w taki sam sposób jak przy wiązaniu statycznym. Można byłoby to nazwać wiązaniem "częściowo statycznym". Co więcej, jeżeli programiści zorientowaliby się, że typy "offsetowe" znacznie poprawiają wydajność zapytań, zaczęliby ich szeroko uzywać, szczególnie tam, gdzie szybkość ma zasadnicze znaczenie.

Emil
Posted: Thursday, March 18, 2010 6:52:55 PM

Rank: Advanced Member

Joined: 10/29/2006
Posts: 50
Points: 147
Location: Warszawa, Polska
Opublikowałem pierwszą oficjalną wersję projektu SBQL4J. Zapraszam na stronę: http://code.google.com/p/sbql4j/
Biblioteka jest dostępna z przykładami (ok. 80 zapytań). Gotowy projekt do uruchomienia w środowisku Eclipse jest dostępny tutaj.

Zapraszam do testowania i dzielenia się uwagami.
rt
Posted: Friday, March 19, 2010 11:28:19 AM
Rank: Member

Joined: 6/2/2005
Posts: 24
Points: -46
Location: mokotow
Emil wrote:
Opublikowałem pierwszą oficjalną wersję projektu SBQL4J. Zapraszam na stronę: http://code.google.com/p/sbql4j/
Biblioteka jest dostępna z przykładami (ok. 80 zapytań). Gotowy projekt do uruchomienia w środowisku Eclipse jest dostępny tutaj.

Zapraszam do testowania i dzielenia się uwagami.


bardzo milo to widziec !!!!!

juz zawodowo nie programuje wiec mi nie przeszkadza ze w javie ;p

poniewaz za bardzo nie mam czasu na analize zrodel, a jednak bardzo mnie ciekawi - zadam pytanie: jak z wsparciem dla indeksow ? bez tego nie ma mowy o sensownej in-memory database
Emil
Posted: Friday, March 19, 2010 11:39:31 AM

Rank: Advanced Member

Joined: 10/29/2006
Posts: 50
Points: 147
Location: Warszawa, Polska
rt wrote:
poniewaz za bardzo nie mam czasu na analize zrodel, a jednak bardzo mnie ciekawi - zadam pytanie: jak z wsparciem dla indeksow ? bez tego nie ma mowy o sensownej in-memory database


W obecnej wersji nie ma indeksów, są iteracje po samych danych.
Na dzień dzisiejszy projekt jest rozszerzeniem języka programowania o zapytania i nie ma wielu cech systemów zarządzania bazami danych jak indeksy, transakcje itp.
W przyszłości zapewne powstaną, jeśli projekt będzie cieszył się choć umiarkowanym zainteresowaniem w społeczności programistów.
rt
Posted: Friday, March 19, 2010 11:51:01 AM
Rank: Member

Joined: 6/2/2005
Posts: 24
Points: -46
Location: mokotow
Emil wrote:
W przyszłości zapewne powstaną, jeśli projekt będzie cieszył się choć umiarkowanym zainteresowaniem w społeczności programistów.


przepraszam za mentorski ton, ale to tak nie dziala.....

wrzucenie linka tu a nawet na *100 popularniejsze fora nie musi skutkowac ekspresja owego zainteresowania

raczej sam powinienes wiedziec co jest warte inwestowanie Twojego czasu a co nie. a ze zycie krutkie czasu warte tylko to co naprawde ciekawe, prawda ?

mysle, ze o zainteresowaniu moze byc mowa gdy biblioteka bedzie sie nadawala do production ready systemow komercyjnyh. w obecnym ksztalcie nie liczyl bym np. na dolaczajacyh sie do projektu developeruw. hoc oczywiscie dobry PR moze zdaialac cuda. tyle ze my jestesmy inzynierami a nie marketingowcami. a czasu malo

czemu Ci to wszytko pisze ? otuz jakis czas temu zrobilem, mysle ciekawa zabaweczke (http://www.darta.art.pl/0) i wlasnie tak jak Ty czekalem na ekspresje owego zainteresowania. wrzucilem linka na channel9 - to jedno z popularniejszyh miejsc dla .net devs. odzew raczej niewielki. domyslam sie ze z powodu takiego ze "0" (nazwa zabaweczki) nie jest dopracowane do konca i do production ready brakuje kilku rzeczy. dlatego nikt sie tym nie interesuje. ja jednak wiem ze koncepcja jest dobra (czego dowodzi np incjatywa oslo microsoftu gdzie w wersji V2 bedzie wlasnie cos podobnego jak moje "0", na razie jest tylko beta V1) i pewnie bede jeszcze "0" rozwijal. gdybym hcial oprzec sie na ekspresji zainteresowania - wyrzucil bym to do kosza ;p
rt
Posted: Friday, March 19, 2010 11:57:23 AM
Rank: Member

Joined: 6/2/2005
Posts: 24
Points: -46
Location: mokotow
tranzakcje oczywiscie bardzo by sie przydaly ale mysle ze z tym wiecej pracy. a takie indeksy to w miare szybko da sie ogarnac. i juz by sie to do czegos nadawalo
Emil
Posted: Friday, March 19, 2010 12:11:06 PM

Rank: Advanced Member

Joined: 10/29/2006
Posts: 50
Points: 147
Location: Warszawa, Polska
W tej chwili projekt stanowi odpowiednik core LINQ dla obiektów w pamięci operacyjnej. Dostępnych jest kilkadziesiąt operatorów, które przykrywają funkcjonalność LINQ, a nawet pozwalają na więcej. Środowisko wykonawcze (w jednym z wariantów) jest równoważne środowisku wykonawczemu programów Java (generowany kod), a więc działanie jest b. szybkie.
Myślę, że już teraz program znajdzie zastosowanie w wielu komercyjnych projektach, których cechują skomplikowane przetwarzanie danych (sam w takich uczestniczyłem), ale oczywiście nie mogę o tym przesądzać.

Jako kierunek rozwoju myślę o opracowaniu architektury integracyjnej opartej na SBQL4J tak, aby możliwe było wywoływanie zapytań na innych systemach przetwarzania zapytań (przetwarzanie dokumentów XML, zdalna baza danych itp)
rt
Posted: Friday, March 19, 2010 12:19:01 PM
Rank: Member

Joined: 6/2/2005
Posts: 24
Points: -46
Location: mokotow
Emil wrote:
Jako kierunek rozwoju myślę o opracowaniu architektury integracyjnej opartej na SBQL4J tak, aby możliwe było wywoływanie zapytań na innych systemach przetwarzania zapytań (przetwarzanie dokumentów XML, zdalna baza danych itp)


to mysle, dosc niebezpieczna droga. czemu? bo po pierwsze dluga i nie wiadomo czy "do przejscia" (moze wystapic wiele problemuw, kture w kontekscie akademickim sa do "przymkniecia oka" ale biz produkcja juz na to nie pozwala) a i nie wiadomo czy znajda sie uzytkownicy tego. nie ma sensu przehodzic ciezkiej drogi (pewnie jest do przejscia, kwesia jakim kosztem) jesli potem nikt z tego nie bedzie korzystal

a takie indeksy by podniosly uzytecznosc Twojego frameworku o rzad wielkosci i to wlasnie w kierunku jaki na pewno znajdzie uzytkownikuw. nawet takie na hybcika - na hasztablah

no to sie pomadrzylem. pozdrawiam i gratuluje jeszcze raz !
Users browsing this topic
Guest


Forum Jump
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.

Main Forum RSS : RSS

Powered by Yet Another Forum.net version 1.9.1.6 (NET v2.0) - 11/14/2007
Copyright © 2003-2006 Yet Another Forum.net. All rights reserved.
This page was generated in 0.265 seconds.