Rode loper gaat uit voor Debian Stretch

Wat hebben Dwight Eisenhower en de OS-software release Stretch met elkaar te maken? Het antwoord staat bij ons op het whiteboard. De Eisenhower methode helpt om relevantie en urgentie van te verrichten werkzaamheden te beoordelen. Hij schijnt ooit te hebben gezegd: ‘The urgent are not important, and the important are never urgent.’

Onderhoud

eisenhower-method

The Eisenhower Method

De servers waarop de diensten draaien die wij onze klanten leveren, moeten onderhouden worden. Bijvoorbeeld door de software te updaten. We willen betrouwbaar meerwaarde leveren: de dienst moet altijd bereikbaar zijn voor onze klanten en doen wat is afgesproken.

Voorbereidingen

De nieuwste versie van het besturingssysteem dat we gebruiken, Debian (URL), heet Stretch en zal naar verwachting begin volgend jaar beschikbaar komen. Om de overgang naar Stretch zo soepel mogelijk te laten verlopen, hebben we nu de nodige voorbereidingen getroffen. Zo is onze Meresco software gepackaged, dus klaar gezet, om straks gemakkelijk te kunnen worden uitgerold op de servers.

Op tijd

Omdat we denken zoals Eisenhower, komt ons werk niet in belangrijk-urgent terecht. Dat is immers de vervelendste plek om te zijn. Tijdige voorbereidingen vergroten het zelfvertrouwen. Bij ons hoeft niemand te wachten op het krijgen van bijvoorbeeld de nieuwste security updates. En wij maken ons niet te laat – dus onnodig -druk.

Autocomplete Zoekplatform passend maken met lokale bibliotheekcollectie

Bij het intikken van een zoekopdracht zijn gebruikers erg geholpen wanneer automatisch mogelijk relevante zoektermen worden gesuggereerd. Het NBC+ zoekplatform biedt deze zogenaamde ‘autocomplete’ functie aan, zodat bibliotheken deze kunnen opnemen in hun website. De NBC+ autocomplete functie biedt bij de de gesuggereerde zoektermen bovendien het type (bijv. een boek of track) van het zoekresultaat dat ermee overeenkomt (zie afbeelding).

Screen Shot 2016-01-14 at 09.10.37

De suggesties waren tot nu toe gebaseerd op alle titels die bekend zijn in de landelijke catalogus. Voor specifieke toepassingen is dat echter onwenselijk, zoals op de website die gericht is op het uitlenen van e-books. Voor een gebruiker zou het hier verwarrend zijn om suggesties te krijgen van titels die niet als e-book beschikbaar zijn. Op dezelfde manier geldt dat een bibliotheek natuurlijk geen suggesties wil geven van materiaal uit een specifieke lokale collectie van een andere bibliotheek.

Op dit moment ontwikkelen we de code die het mogelijk maakt de suggesties te beperken tot precies het deel van de nationale collectie dat een lokale bibliotheek daadwerkelijk aanbiedt op haar website. Zo vinden gebruikers nog makkelijker wat ze zoeken.

 

Wat Botswana en Nederland gemeenschappelijk hebben…

Zo aan het eind van het jaar is het een goed moment om terug te kijken. Kijken we wat langer terug, dan zien we dat er verandering komt in een slepende situatie: in Nederland investeren overheid en non-profit organisaties jaarlijks voor miljoenen in kostbaar onderzoek. De research output is echter zelden beschikbaar voor het publieke domein, want het wordt gecopyright door uitgeverijen. U vindt de opgedolven wijsheid dus niet voor iedereen toegankelijk in de daarvoor bedoelde Universiteitsbibliotheken. Ze wordt daardoor onderbenut voor het algemeen belang. Ook in een land als Botswana, dat net zo goed kennis hard nodig heeft, speelt dit probleem. Maar er lijkt een doorbraak te zijn om deze ‘tragedy of the commons’ te doorbreken.

Subsidie onder voorwaarde

Sinds deze maand geeft NWO in Nederland alleen nog subsidies aan onderzoeken, die hun publicatie openbaar toegankelijk maken. Dat helpt. Wie de leiding in Botswana neemt om de tragedie te doorbreken, kan ik u zo even niet vertellen, behalve dat ook zij al heel lang behoefte aan toegang tot informatie hebben voor onderwijs en research, om een duurzame ontwikkeling te realiseren.

Narcis

In 2008 besloten wij om die reden onder andere dit land via de non-profit organisatie Eifl (Electronic Information for Libraries) aan een systeem te helpen, dat lijkt op Darenet. In Nederland werd dit de voorloper van Narcis. In Narcis is goed te zien welke publicaties ‘open access’ zijn.

Blog illustratie Botswana Nederland

December is een goede maand om te bedenken dat wij, terugkijkend, misschien een steentje bijdroegen aan de groei van de ‘open access’ beweging, in Nederland, èn in Botswana.

Wie mag wat waar: integrated access management

Om eindgebruikers van het zoekplatform van bibliotheek.nl toegang te geven tot andere bibliotheekdiensten, schrijven we nu code voor een goede afhandeling daarvan. Dit stukje functionaliteit laat de systemen van de bibliotheek weten met wie ze te maken hebben, zonder dat daarbij passwords of inlogcodes van de gebruiker bij het zoekplatform zelf bekend hoeven te zijn. De afhandeling vindt plaats via OAuth 2.0. Deze service geeft een ‘sleutel’ af bij het inloggen, en herkent die als er gevraagd wordt een actie uit te voeren. Boekje lenen? Is goed. Reserveren? Kan! Vanaf de kant van de bibliotheek gezien, biedt deze toegangspoort een prettige flexibiliteit in de dienstverlening. Er zijn immers legio diensten denkbaar, die achter zo’n intelligente toegangspoort beheersbaar uitgerold kunnen worden. Voor de huidige case beperken we ons tot het reserveren van boeken.

Handig voor de opdrachtgever is dat we de uitwerking van ons voorstel op onze demo-pagina zetten. Daarmee kunnen we snel laten zien hoe zaken werken, en kunnen we alternatieven of coole features tonen.

WaaS 2.0 aansluiting op NBC+

Stichting Bibliotheek berichtte recent dat in de komende maanden de landelijke diensten volledig worden geïntegreerd in WaaS 2.0. Het gaat hierbij onder andere om de content en functionaliteiten op www.bibliotheek.nl: de pagina’s over e-books, jeugd, literatuur en WelkBoek. Ook wordt landelijk zoeken op basis van de NBC+ opgeleverd.

Hiermee wordt de door Seecr ontwikkelde zoekmachine de motor achter deze functies.

Voordelen aansluiting NBC+
De aansluiting van WaaS 2.0 op het Zoekplatform biedt tal van nieuwe mogelijkheden en functies. Naast bronnen zoals kranten, e-books en de consumentengids, worden ook alle lokale bronnen van bibliotheken opgenomen in het landelijk Zoekplatform en zullen er in de toekomst nog meer volgen, zoals bijvoorbeeld de Digitale Collectie.

Tegelijk komen ook centrale functies voor iedereen beschikbaar. Wat lokaal vaak niet mogelijk is, kan centraal wel worden geregeld. Denk bijvoorbeeld aan deduplicatie en het uniformeren van metadata. Het mooie is dat het dan over al deze bronnen heen gebeurt, in plaats van binnen één collectie.

Uniformeren van auteurs
Een voorbeeld van een nieuwe functie is het uniformeren van auteurs en onderwerpen. Verschillende bronnen hebben vaak een eigen manier om te refereren aan auteurs. Op basis van de verzamelde gegevens, gaan wij de identifiers over dezelfde auteurs op elkaar afbeelden. We werken hierbij onder meer met Wikipedia, GTAA, NTA en Viaf. Al deze data is/wordt als Linked Open Data gepubliceerd.

Een analoog verhaal geldt voor onderwerpen of trefwoorden. Iedereen heeft zo zijn eigen classificatiesysteem, vaak meerdere binnen dezelfde collectie. Het verzamelen van de gegevens en het bij elkaar zoeken van de overeenkomsten is in volle gang. De planning is om in 2015 grote stappen te kunnen zetten.

Vooruitblik
Wij zijn enthousiast over de aansluiting van WaaS 2.0 op het NBC+. Een goed startpunt van een mooie doorontwikkeling van het Zoekplatform die het voor elke bibliotheek mogelijk maakt om het hele Nederlandse Erfgoed te relateren aan haar eigen collectie.

Multi-threaded expert search with Lucene

Lucene’s high-level search API parallelizes search automatically, achieving superb performance.

The low-level expert API does not do that.  Here is a solution to parallelize custom search. It is Open Source.

Introduction

The Open Source search engine Lucene has evolved into a very smart and efficient search tool.  It offers both high level search interfaces as well as low-level (expert) interfaces. If you pass it an Executor, the high-level interface (API) automatically enables all the CPU’s in a server to work on your queries as fast as possible.  The results are downright fantastic.  For quite large data sets and quite complicated queries, you will get results in milliseconds.

Concurrency and the expert interface

However, the low-level API does not put all your cores to work automatically.  That means that as soon as queries become more complicated and you have to use the low-level API, it runs slower.  That is not a problem as long as you limit the number of documents to, say, 10,000,000. Most functionality like sorting and facets still runs in a few 100 of milliseconds. But when you have many more documents and when you must support many concurrent queries, the help of more CPU’s would be very nice.

Before I introduce our solution, a quick word about the so-called expert API and the problem with it.

How the low-level API works: Collector

The main work of any search engine consists of intersecting, intersecting and yet more intersecting. Lucene’s low-level expert API gives a programmer access to the inner loop that performs the intersecting. Lucene has a hook that, regardless of what intersection algorithm it uses (zip, gallop, bisect, skip lists, and so on, look for “integer intersection algorithms”), it calls your code as soon as it determines a document is in the set defined by your query.

The hook consists of an interface called Collector, that has a method collect().  When you pass an object that supports this interface, Lucene will call collect() for each result.  This method must be very short, small and fast, since Lucene will call it many, many times.

The problem is that the search methods that accept a Collector do not enable threads and leave all but one of your CPU’s idle.  There is a good reason for that.

The problem with Collectors

The Collector interface is inherently thread-unsafe.  The reason for this is the way the setNextReader() method on Collector works. Internally, Lucene maintains an index composed of tens of segments each containing a subset of the complete index.  During search, Lucene tells the collector that a new segment starts and that the following calls to collect() are in the context of this segment.  All but the most trivial Collectors need to remember this context and this is why the Collector is unsuitable for multi-threading.  What if two threads call setNextReader() with different arguments?

Using Lucene’s internal segmenting to divide the work is quite natural. Indeed, the high-level API divides the work based on segments.  What if custom Collectors could also use this?

SuperCollector and SubCollector

We designed two new interfaces that are much like the Collector, but just different enough to support multi-threaded search for any operation.  The first is SuperCollector.  It basically replaces Collector in the call to search().  So instead of (pseudocode):

searcher.search(query, filter, collector)

we use:

searcher.search(query, filter, supercollector)

That’s all.

The SuperCollector creates subCollectors that are thread-safe:

subcollector = supercollector.subCollector(...)

The new search() method calls the method subCollector() for as many threads it wants to create. SubCollector is almost identical to Collector.  If fact, it is a subclass of Collector. It supports the setNextReader() and setScorer() methods and of course collect() and it adds only one more method:

subcollector.complete()

The thread executing the search calls complete() after it is finished. Some collectors do most of their work during collect() calls, but others just collect data for post-processing later.  Such collectors can put time-consuming post-processing in the complete() method so that it executes in parallel as well.

Encapsulating existing code

The nasty thing about the Collector API is that once you start using it, the simple parts of your query, that used to be automatically parallelized by Lucene, will now be single-threaded as well. Therefore we also need to create Super/SubCollectors for simple queries.

Simple queries are queries with results sorted on score or on a field value. The parallelization is spread across the Lucene code. We found it and encapsulated it as follows:

  1. Some code in the search method at lines 450-456 and lines 535-547 creates the threads.  We replace this code with one generic piece in search().
  2. Code for creating the TopFieldCollector at line 535 for sorting on a field while the case for sorting on score is degelated to SearcherCallableNoSort which will delegate further until a TopScoreDocCollector is finally created at line 490. We encapsulate this in specific subCollector() methods.
  3. Code for merging the results at lines 460-471 (sort on score) and at lines 550-559 (sort on field). We encapsulate this in SuperCollector.

Example: TopFieldSuperCollector

Here are the results for applying the encapsulation outlined above to the way Lucene’s default TopFieldCollector works.  These are the important steps:

First, the TopDocsSuperCollector creates the proper SubCollector when search() asks for it:

TopFieldSubCollector
createSubCollector() {
    return new TopFieldSubCollector(...);
}

The search continues as normal.  Lucene calls collect() for each result found, but this happens in a thread.  The TopFieldSubCollector simply delegates to a standard Lucene TopFieldCollector.

The search signals completion of the segment by calling complete(), which simply delegates again:

void complete() {
    this.topdocs = this.delegate.topDocs()
}

Finally, the merge happens when the application asks for the result by calling topDocs():

TopDocs topDocs(int start) {
    for (TopFieldSubCollector sub : super.subs) {
        // merge results from subcollectors
    }
    return topDocs
}

What next?

The concept above has been implemented for simple search and shows very much speed-up.  We now have to create Super- and SubCollectors for the other functions we use:

  1. for sorting by relevance: TopDocsCollector
  2. for calculating facets: FacetCollector
  3. for creating trees of collectors: MultiCollector
  4. for de-duplicating results: DeDupCollector
  5. for query-time join: KeyCollector and ScoreCollector

For each of them we are working out the design and then we will add them. I will post the results when we are done.

Meanwhile, you can follow the code here: Meresco Lucene.

Perfecte match met XFS

Bij toeval hebben we ontdekt dat XFS  een perfecte match is met de door ons recent ontwikkelde SequentialStorage. XFS is een file system dat we al jaren gebruiken, maar dat het zo’n goede combinatie is, hadden we van tevoren niet verwacht.

Laatst constateerden we in Gustos, ons systeem voor Continubeheer, een fikse toename van diskverbruik die niet in verhouding stond met de toename van de data. Om dit te kunnen verklaren, zijn we in het file system gedoken.

We hebben ontdekt dat XFS  bestanden herkent waar veel naar wordt geschreven. Bij die bestanden wordt extra aaneengesloten ruimte gereserveerd. De gereserveerde ruimte wordt door de standaard tooling aangegeven als zijnde ‘in gebruik’. Na onderzoek en de juist tool de goede vraag te stellen, kwamen we erachter dat XFS tijdig de gereserveerde ruimte automatisch weer vrijgeeft als er een ruimtetekort ontstaat. Goed geregeld!

SequentialStorage
Dat XFS de ruimte weer vrijgeeft, is wat wij willen voorkomen. Die ruimte werkt juist in het voordeel met SequentialStorage. Dit onderwerp is de moeite waard om een apart technisch artikel aan te wijden. Maar kort samengevat hebben we SequentialStorage ontwikkeld omdat we vaak tussen systemen dezelfde stroom data in dezelfde volgorde moeten ophalen. Door alle records achter elkaar op te slaan, is het haalbaar om data snel en sequentieel op te leveren.

Als wij weer signaleren dat de disk vol dreigt te lopen, weten wij wat ons te doen staat.  Wij geven XFS graag de ruimte.