Gabi und Sascha
Tags - Kategorien : Alle | Berlin | Bücher | Fotografie | Java | Linkhalde | Weichware | Verfassung

Das letzte Glied der Backend-Kette für eine Entity Oriented Search ist fertig.

In einem ersten Schritt habe ich Medline Abstracts in Sätze zerlegt und eventuell doppelt vorhandene heraus gefiltert. In einem zweiten Schritt habe ich relevante Konzepte identifiziert (Erkenntnisse darüber in HadoopTestCase und der DistributedCache). Hierfür habe ich einen firmeneigenen Thesaurus verwendet - die Identifikation wurde mittels eines Tries durchgeführt.

Für jedes Konzept habe ich zu jedem Jahr, in welches es vorkommt, alle Sätze zusammen gefasst. In diesem letzten Schritt wurden diese Konzept-Jahr-Satz Tupel in einen Lucene Index überführt. Die Basis dafür hat Christian geschrieben und ich habe seinen Basis übernommen und für meine Anforderungen angepasst. Um den Index nach dem optimieren zu prüfen wurde wieder ein HadoopTestCase erstellt. Der Index wird aus Testdaten erstellt. Um ihn zu testen, muss der Zielpfad allerdings um "merge-output" erweitert werden (hart codiert in IndexMerger).

Job Konfiguration:


    final JobConf jobConf = createJobConf();
    jobConf.setMapperClass(IndexingMapper.class);
    jobConf.setReducerClass(IndexingReducer.class);
    jobConf.setJobName("testindex");
    jobConf.setOutputFormat(OutputFormatLucene.class); // von Christian
    jobConf.setOutputValueClass(Text.class);

Mapper:


    public void map(final K key,
                    final Text value,
                    final OutputCollector output, 
                    final Reporter reporter) throws IOException {
        // hier passiert gar nix.
        output.collect(key, value);
    }

Reducer:


    public void reduce(final K key,
                       final Iterator lineIterator,
                       final OutputCollector output,
                       final Reporter reporter) throws IOException {
        while (lineIterator.hasNext()) {
            final Text textValue = lineIterator.next();
            final Document doc = createDocumentFromText(textValue, reporter);

            if (doc != null) {
                output.collect(key, new ObjectWritable(doc));
            }
        }
    }

Nach der Abarbeitung des Jobs:


    import org.apache.nutch.indexer.FsDirectory;
    import org.apache.nutch.indexer.IndexMerger;

    final FileSystem fs = FileSystem.get(jobConf);
    final IndexMerger merger = new IndexMerger(jobConf);
    merger.merge(fs.listPaths(new Path[] {inputPath}), 
                 outputPath,
                 new Path(outputPath, "tempdir"));

    final FsDirectory dir =
        new FsDirectory(fs,
                        new Path(this.resultPath, "merge-output"),
                        false,
                        jobConf);
    final IndexSearcher searcher = new IndexSearcher(dir);
    searcher.setSimilarity(new NormedLengthSimilarity());

    final QueryParser qp = new QueryParser(CONTENT.name(),
                                           OutputFormatLucene.ANALYZER);
    final String escaped = QueryParser.escape("urn:123");

    final Query q = qp.parse(CONTENT.name() + ":\"" + escaped + "\"");
    final Hits hits = searcher.search(q);

    assertEquals(2, hits.length());
    searcher.close();

Als nächstes muss ich den kompletten Index zweimal erstellen. Einmal mit den Lucene Bord-Mitteln und einmal mit einer angepassten Similarity. Hierbei wird beim Indexieren die lengthNorm auf 1.0f gesetzt, damit kurze Dokumente nicht bevorzugt gewertet werden. Ein einfaches Web-Frontend soll dann suchen und vergleichen ermöglichen.