Generator für Stellenanzeigen

vorhergehende Artikel in: Java Komponenten
27.09.2023

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

Alle Artikel rss Wochenübersicht Monatsübersicht Github Repositories Gitlab Repositories Mastodon Über mich home xmpp


Vor 5 Jahren hier im Blog

  • Mandelbrot-Sets mittels Shadern berechnen

    17.05.2019

    Nachdem ich in den letzten verregneten Tagen auf Youtube in den Videos von Numberphile versunken bin, hat mich eines davon angestachelt, mich selbst mit dem Mandelbrotset zu beschäftigen. Als ich dann noch Code fand, der behauptete, das auf einer Graphikkarte mittels Shadern berechnen zu können, war es um mich geschehen...

    Weiterlesen...

Neueste Artikel

  • Erste Vor-Version eines Gis-Plugin für die sQLshell

    Wie bereits in einem früheren Artikel erwähnt plane ich, demnächst ein Plugin für die sQLshell anzubieten, das eine Visualisierung von Daten mit räumlichem Bezug im Stil eines Geoinformationssystems erlaubt.

    Weiterlesen...
  • bad-certificates Version 2.1.0

    Das bereits vorgestellte Projekt zur automatisierten Erzeugung von Zertifikaten mit allen möglichen Fehlern hat eine Erweiterung erfahren und verfügt über ein Partnerprojekt - beide sind nunmehr in der Version 2.1.0 freigegeben

    Weiterlesen...
  • SQLite als Geodatenbank

    Wie bereits in einem früheren Artikel beschrieben treibe ich derzeit Anstrengungen voran, die sQLshell attraktiver für Nutzer zu machen, die mit Geodatenbanken arbeiten.

    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, muß 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 GitHub-Repositories findet man hier - meine öffentlichen GitLab-Repositories finden sich dagegen hier.