org.arastreju.sge.spi.impl.LuceneBasedNodeKeyTable.java Source code

Java tutorial

Introduction

Here is the source code for org.arastreju.sge.spi.impl.LuceneBasedNodeKeyTable.java

Source

/*
 * Copyright (C) 2013 lichtflut Forschungs- und Entwicklungsgesellschaft mbH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.arastreju.sge.spi.impl;

import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.NumericField;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.arastreju.sge.naming.QualifiedName;
import org.arastreju.sge.persistence.NodeKeyTable;
import org.arastreju.sge.spi.PhysicalNodeID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;

/**
 * <p>
 *  Node key table based on a lucene index.
 * </p>
 *
 * <p>
 *  Created Mar 22, 2013
 * </p>
 *
 * @author Oliver Tigges
 */
public abstract class LuceneBasedNodeKeyTable<T extends PhysicalNodeID> implements NodeKeyTable<T> {

    private static final Logger LOGGER = LoggerFactory.getLogger(LuceneBasedNodeKeyTable.class);

    public static final String PID = "pid";

    public static final String QN = "qn";

    // ----------------------------------------------------

    private final Directory dir;

    private final IndexWriter writer;

    // ----------------------------------------------------

    public static LuceneBasedNodeKeyTable<NumericPhysicalNodeID> forNumericIDs(String baseDir) throws IOException {
        return new LuceneBasedNodeKeyTable<NumericPhysicalNodeID>(baseDir) {
            @Override
            protected NumericPhysicalNodeID createID(Document doc) {
                NumericField field = (NumericField) doc.getFieldable(PID);
                return new NumericPhysicalNodeID(field.getNumericValue());
            }

            @Override
            protected void setID(Document doc, NumericPhysicalNodeID id) {
                NumericField field = new NumericField(PID, Field.Store.YES, false);
                field.setLongValue(id.asLong());
                doc.add(field);
            }
        };
    }

    // ----------------------------------------------------

    protected LuceneBasedNodeKeyTable(String baseDir) throws IOException {
        final File indexDir = new File(baseDir, "__qn_index");
        LOGGER.info("Creating node key table index in {}.", indexDir);
        boolean created = indexDir.mkdir();
        IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_35,
                new StandardAnalyzer(Version.LUCENE_35));
        this.dir = FSDirectory.open(indexDir);
        this.writer = new IndexWriter(dir, config);
        if (created) {
            LOGGER.info("Index directory newly created. Starting initialization.");
            writer().commit();
        }
    }

    // ----------------------------------------------------

    @Override
    public T lookup(QualifiedName qualifiedName) {
        TermQuery query = new TermQuery(new Term(QN, qualifiedName.toURI()));
        IndexReader reader = reader();
        try {

            IndexSearcher searcher = new IndexSearcher(reader);
            TopDocs result = searcher.search(query, 2);
            searcher.close();

            if (result.scoreDocs.length == 1) {
                Document document = reader.document(result.scoreDocs[0].doc);
                return createID(document);
            } else if (result.scoreDocs.length == 0) {
                return null;
            } else {
                throw new IllegalStateException(
                        "Found more than one document for qualified name: " + qualifiedName);
            }
        } catch (IOException e) {
            throw new RuntimeException("Could not query by qualified name.", e);
        } finally {
            try {
                reader.close();
            } catch (IOException e) {
                throw new RuntimeException("Could not close index reader.", e);
            }
        }
    }

    @Override
    public synchronized void put(QualifiedName qn, T physicalID) {
        Document doc = new Document();
        doc.add(new Field(QN, qn.toURI(), Field.Store.YES, Field.Index.NOT_ANALYZED));
        setID(doc, physicalID);
        try {
            final IndexWriter writer = writer();
            writer.addDocument(doc);
            writer.commit();
        } catch (IOException e) {
            throw new RuntimeException("Could not map phyiscal ID to qualified name in index.", e);
        }
    }

    @Override
    public void remove(QualifiedName qn) {
        try {
            final IndexWriter writer = writer();
            writer.deleteDocuments(new Term(QN, qn.toURI()));
            writer.commit();
        } catch (IOException e) {
            throw new RuntimeException("Could not remove qualified name from index.", e);
        }
    }

    @Override
    public void shutdown() throws IOException {
        writer.close();
        dir.close();
    }

    // ----------------------------------------------------

    protected abstract T createID(Document doc);

    protected abstract void setID(Document doc, T id);

    // ----------------------------------------------------

    private IndexReader reader() {
        try {
            return IndexReader.open(dir, true);
        } catch (IOException e) {
            throw new RuntimeException("Unable to obtain an index reader.", e);
        }
    }

    private IndexWriter writer() throws IOException {
        return writer;
    }

}