2015-09-23 12 views
5

Bir veritabanını jooq ile sorgulamanın ve sonucu akışlarla işleme koymanın bir bileşimi var. Ancak, kodumun çok okunamadığını ve yeterince kısa olmadığını hissediyorum. Kuralımı, niyetimi daha iyi ifade etmenin yolları konusunda nasıl geliştirebilirim.Toplama sırasında çoklu akış engellenmesi nasıl olur?

sql 
    .select(field("USER_NAME", String.class)) 
    .from(table("CWD_USER")) 
    .fetch() 
    .stream() 
    .map(f -> f.getValue(field("USER_NAME", String.class))) 
    .collect(Collectors.groupingBy(s -> StringUtils.split(s, "-")[0], Collectors.counting())) 
    .entrySet().stream() 
    .sorted(new java.util.Comparator<Entry<String, Long>>() { 
     @Override 
     public int compare(Entry<String, Long> o1, 
       Entry<String, Long> o2) { 
      return o2.getValue().compareTo(o1.getValue()); 
     } 
    }) 
    .forEach(e -> System.out.println(String.format("%13s: %3d", e.getKey(), e.getValue()))); 

İlk Birden çok akışta sorun yaşıyorum. İlk önce jooq’tan akışı başlattım, sonra toplanan haritayı akıtıyorum. Ayrıca karşılaştırıcı öne çıkmaktadır. Elbette bir ders çıkarabilirim ama belki başka bir çözüm var.

+3

[ 'Map.Entry.comparingByValue (...) (http://docs.oracle.com/javase/8/docs/api/java/util/Map.Entry.html#comparingByValue--), neden kullanmak zorunda olduğunuzu düşündüğünüzü anlamıyorum Kodunuzdaki diğer yerlerde lambda ifadelerini daha önce bildiğiniz gibi, "Karşılaştırıcı" için iç sınıf. – Holger

+1

Sadece referans için karşılık gelen lambda, .sorted ((o1, o2) -> o2.getValue(). CompareTo (o1.getValue())) 'olacaktır. Bunu işaretlediğiniz için teşekkürler @Holger. –

+0

'İlk önce jooq’tan bir sonuç yayınlıyorum sonra toplanan haritayı akıtıyorum - hayır. Sonuçları jooq'dan akıtıyorsunuz ve o da. Örneğinizde gösterilen ek akışlar yoktur, birkaç ara işlem ve tek bir terminal işlemiyle tek bir akış. Bu nasıl akışları çalışır. Eğer akarsuların temel işlevlerini "önlemek" istiyorsanız, klasik foreach/for/while - döngüler kullanmanız gerekir. Ama dürüstçe: bu bir downgrade olurdu ... akışlar çok özlü ve güzel - kendi kodunuz bunu gösterir. Aynı işlevsellik, akışlar olmadan en az 100 satırlık kod gerektirebilir. – specializt

cevap

5

JOOQ bölümü hakkında bir şey söyleyemiyorum, ancak Stream API kısmı iyi görünüyor. Sıralamadan önce sayıları bilmek için ara sıra toplamak zorundasınız. Böyle bir karşılaştırıcının JDK'da zaten uygulandığını unutmayın: Map.Entry.comparingByValue(). Sen (ters sırada sıralamak için Comparator.reverseOrder() parametresini ekleyin), kullanabileceği:

sql 
    .select(field("USER_NAME", String.class)) 
    .from(table("CWD_USER")) 
    .fetch() 
    .stream() 
    .map(f -> f.getValue(field("USER_NAME", String.class))) 
    .collect(Collectors.groupingBy(s -> StringUtils.split(s, "-")[0], Collectors.counting())) 
    .entrySet().stream() 
    .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())) 
    .forEach(e -> System.out.println(String.format("%13s: %3d", e.getKey(), e.getValue()))); 
2

bu daha karmaşık bir sorgu bir ölçüde basitleştirilmiş bir versiyonudur sürece, SQL tüm mantığı taşımak istiyorum. jOOQ ile,

SELECT PREFIX, COUNT(*) 
FROM (
    SELECT SUBSTR(USER_NAME, 1, INSTR(USER_NAME, '-') - 1) AS PREFIX 
    FROM CWD_USER 
) T 
GROUP BY PREFIX 
ORDER BY COUNT(*) 

Veya: (Oracle lehçesini kullanarak) eşdeğer SQL sorgusu size varlığını bilmek bile

sql.select(field("PREFIX", String.class), count()) 
    .from(
    select(substring(
     field("USER_NAME", String.class), 
     inline(1), 
     position(field("USER_NAME", String.class), inline("-")).sub(inline(1)) 
    ).as("PREFIX")) 
    .from(table("CWD_USER")) 
    ) 
    .groupBy(field("PREFIX", String.class)) 
    .orderBy(count()) 
    .fetch(); 
İlgili konular