Ich habe neulich wieder einmal einen neuen Testdatengenerator geschrieben, den ich mit Daten aus der Perrypedia fütterte.
Inspiriert wurde ich von einem Generator für Jobangebote im Startrek-Universum.
Und da ich immer noch der Meinung bin, dass LLMs eine pure Verschwendung von Ressourcen sind wollte ich sehen, ob ich mit einer einfachen Markovkette nicht etwas ähnliches schaffen könnte.
Um die Datenquellen nicht über Gebühr zu belasten erstellte ich zunächst eine Klasse, die eine Datei aus dem Netz herunterlädt und lokal chached. Dies sollte für den Anwendungscode vollständig transparent geschehen. Der Code sollte dabei die Angaben zur Lebenszeit der Ressource berücksichtigen und entsprechend der Informationen vom Server automatisch eine neue Version herunterladen wenn diese abgelaufen wäre.
Dabei kam der folgende Code heraus:
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.time.Clock;
public class CachedAndDownloadedResource extends java.lang.Object
{
private final static org.slf4j.Logger CLASS_LOGGER =org.slf4j.LoggerFactory.getLogger(CachedAndDownloadedResource.class);
private final static org.slf4j.Logger EXCEPTION_LOGGER =org.slf4j.LoggerFactory.getLogger("ExceptionCatcher");
private final java.net.URL url;
private final java.io.File cachedFile;
private final long maxAgeInSeconds;
public CachedAndDownloadedResource(java.net.URL url) throws NoSuchAlgorithmException, IOException
{
this(url,-1);
}
public CachedAndDownloadedResource(java.net.URL url, long maxAgeInSeconds) throws NoSuchAlgorithmException, IOException
{
super();
if(url==null)
throw new java.lang.IllegalArgumentException("url must not be null!");
this.url=url;
this.maxAgeInSeconds=maxAgeInSeconds;
java.lang.String urls=url.toString();
java.security.MessageDigest digest = java.security.MessageDigest.getInstance("SHA-512");
byte[] encodedhash = digest.digest(urls.getBytes(java.nio.charset.StandardCharsets.UTF_8));
java.lang.String hash=de.elbosso.util.Utilities.formatHexDump(encodedhash,false);
CLASS_LOGGER.debug(java.text.MessageFormat.format("encodedhash {0}",hash));
java.io.File cacheDir=de.elbosso.util.Utilities.getCacheDirectory();
cachedFile=new java.io.File(cacheDir,hash);
java.net.URLConnection conn=de.elbosso.util.Utilities.openConnectionFollowingRedirects(url);
java.lang.String cacheControl=conn.getHeaderField("Cache-Control");
CLASS_LOGGER.debug(java.text.MessageFormat.format("Cache-Control for {0} is {1}",url,cacheControl));
if(((cacheControl.contains("private"))||(cacheControl.contains("must-revalidate")))&&(maxAgeInSeconds<1))
{
CLASS_LOGGER.debug("caching not allowed!");
}
else
{
if (cachedFile.exists() == false)
{
download();
}
else
{
CLASS_LOGGER.debug(java.text.MessageFormat.format("found cached file for {0}", url));
java.time.Instant fileInstant = java.nio.file.Files.getLastModifiedTime(java.nio.file.Paths.get(cachedFile.toURI())).toInstant();
java.time.Instant now = Clock.systemDefaultZone().instant();
java.time.Duration difference = java.time.Duration.between(fileInstant, now);
long millis = difference.toMillis();
CLASS_LOGGER.debug(java.text.MessageFormat.format("cached file is {0} seconds old", (millis / 1000)));
java.lang.String[] parts = cacheControl.split(",");
long maxAge = maxAgeInSeconds;
for (java.lang.String part : parts)
{
if (part.startsWith("max-age="))
{
long time=java.lang.Long.parseLong(part.substring(8));
if(maxAge>time)
maxAge=time;
break;
}
}
CLASS_LOGGER.debug(java.text.MessageFormat.format("max age of {0} is {1}", url, maxAge));
if (maxAge > -1)
{
if (maxAge < millis / 1000)
{
download();
}
}
}
}
}
private void download() throws IOException
{
CLASS_LOGGER.debug(java.text.MessageFormat.format("downloading from {0}", url));
java.io.FileOutputStream fos = new java.io.FileOutputStream(cachedFile);
de.elbosso.util.Utilities.copyFromURLIntoStream(url, fos, true, true);
}
public java.io.InputStream openStream() throws IOException
{
java.io.InputStream rv=cachedFile!=null?new java.io.FileInputStream(cachedFile):null;
if(rv!=null)
{
rv=de.elbosso.util.Utilities.openConnectionFollowingRedirects(url).getInputStream();
}
return rv;
}
public java.time.Instant getLastModifiedDate() throws IOException
{
return cachedFile!=null?java.nio.file.Files.getLastModifiedTime(java.nio.file.Paths.get(cachedFile.toURI())).toInstant():java.time.Instant.now(Clock.systemDefaultZone());
}
}
Damit war es mir möglich, die benötigten Daten für den Generator einzusammeln, was dann zu folgenden Beispielen für Stellenanzeigen im Peryversum führte:
Politbüro 610 sucht ab sofort ein Team von 3 Mitarbeitern, darunter
mindestens ein Paradimingenieur, idealerweise ein weiterer Historiker. Bewerber
von folgenden Welten oder vergleichbaren Umweltbedingungen werden bevorzugt
berücksichtigt: Strega und Drackrioch. Erfahrungen bezüglich Audikom und
Zweikomponenten-Absorber von mindestens 1 Standardjahren müssen zwingend nachgewiesen
werden. Der Vertrag ist unbefristed. Die Stationierung erfolgt an Bord von KABBACH
- Dienstantritt erfolgt auf Central-Station. Bewerber kontaktieren bitte umgehend
Algiotische Wanderer. Ihre Bewerbung wird zentral gesammelt und an Ti-Than
zur Bearbeitung weitergeleitet.
Für eine Expedition in Richtung Milchstraße suchen wir für nächstes Jahr
einen Planforming-Ingenieur. Bewerber aus den Völkern Pers-Oggaren, Treidever,
Argots und Truzenen oder vergleichbaren Umweltbedingungen von Vorteil.
Kenntnisse bezüglich Individualschloss, Positronischer Schlüssel, Strukturabsorber
und Biogen-Regenerator von Vorteil. Erfahrungen bezüglich Hypertraktor und
Estartische Technik von mindestens 10 Standardjahren müssen zwingend nachgewiesen
werden. Der Vertrag ist unbefristed. Die Stationierung erfolgt an Bord von
BOX-3206 - Dienstantritt erfolgt auf Lysum 1.
Damurial sucht für nächstes Jahr ein Team von 2 Mitarbeitern, darunter
mindestens ein Waffeningenieur, idealerweise ein weiterer Butler. Bewerber
aus den Völkern Koyter, Obugaab, Skaerhams und Craahzz oder vergleichbaren
Umweltbedingungen von Vorteil. Geplante Dauer das Vertrages: 31 solare Monate
mit Option auf Verlängerung. Die Stationierung erfolgt an Bord von RALPH
SIKERON - Dienstantritt erfolgt auf GEUZA. Bewerber kontaktieren bitte
umgehend Fracowitz-Systemstaaten. Ihre Bewerbung wird zentral gesammelt und
an Space Academy zur Bearbeitung weitergeleitet.
Wegen Stigmavirus sucht Unionsrat ab sofort einen Psychochirurg.
Bewerber aus den Völkern Peikomäer, Karoky und Kraqueker oder vergleichbaren
Umweltbedingungen von Vorteil. Kenntnisse in Sprache und Sozialstruktur
folgender Völker sind extrem hilfreich: Barbassen, Vendoori und Skinen.
Der Vertrag ist unbefristed. Einsatzort ist TV-8-Sol mit gelegentlichen
Abordnungen. Bewerber kontaktieren bitte umgehend Koalition Thoregon. Ihre
Bewerbung wird zentral gesammelt und an Extraterrestrial Field Service
zur Bearbeitung weitergeleitet.
Wegen Explosive Zellteilung suchen wir für nächstes Jahr ein Team von 4
Mitarbeitern, darunter mindestens ein Planformarchitekt, idealerweise ein
weiterer Trümmerscout. Bewerber von folgenden Welten oder vergleichbaren
Umweltbedingungen werden bevorzugt berücksichtigt: Taffstav, Kolton und
Rasterstop III. Kenntnisse bezüglich Psionischer Stempel und Totenbrünne
von Vorteil. Erfahrungen bezüglich Ishara und Antipsischirm von mindestens
15 Standardjahren müssen zwingend nachgewiesen werden. Der Vertrag ist
unbefristed. Einsatzort ist Bressor
01.11.2024
Nachdem es nun bereits seit einiger Zeit ein wenig stiller um meine diversen Generatoren für Testdaten geworden ist, habe ich über den Feiertag in Thüringen einen neuen begonnen.
Multi-User-WebDAV, Docker, GitHub
17.11.2019
Nachdem ich mich in letzter Zeit verstärkt mit Docker und dem zugehörigen Ökosystem beschäftige, habe ich begonnen, verschiedenste Dienste in Containern zu testen um zu sehen, ob in manchen Fällen LXC oder KVM nicht doch die bessere Wahl wäre...
Weiterlesen...Android Basteln C und C++ Chaos Datenbanken Docker dWb+ ESP Wifi Garten Geo Go GUI Gui Hardware Java Jupyter Komponenten Links Linux Markdown Markup Music Numerik OpenSource PKI-X.509-CA Python QBrowser Rants Raspi Revisited Security Software-Test sQLshell TeleGrafana Verschiedenes Video Virtualisierung Windows Upcoming...
In eigener Sache...
Weiterlesen...Ich habe eine neue Java Swing Komponente erstellt: Es handelt sich um einen Wrapper für von JToolBar abgeleitete Klassen, die die Werkzeugleiste minimieren und sie nur dann einblenden, wenn der Mauszeiger über ihnen schwebt.
Weiterlesen...Ich habe bereits in einem früheren Artikel über meine ersten Erfolge berichtet, der sQLshell auf Basis des bestehenden Codes aus dem Projekt EBMap4D eine bessere Integration für Geo-Daten zu spendieren und entsprechende Abfragen, bzw. deren Ergebnisse auf einer Kartenansicht zu visualisieren.
Weiterlesen...Manche nennen es Blog, manche Web-Seite - ich schreibe hier hin und wieder über meine Erlebnisse, Rückschläge und Erleuchtungen bei meinen Hobbies.
Wer daran teilhaben und eventuell sogar davon profitieren möchte, muss damit leben, daß ich hin und wieder kleine Ausflüge in Bereiche mache, die nichts mit IT, Administration oder Softwareentwicklung zu tun haben.
Ich wünsche allen Lesern viel Spaß und hin und wieder einen kleinen AHA!-Effekt...
PS: Meine öffentlichen Codeberg-Repositories findet man hier.