Changing the models that the SearchReindexingListener listens to. NIHVIVO-2076
This commit is contained in:
parent
61812f7a1e
commit
1341d23a25
10 changed files with 327 additions and 323 deletions
|
@ -5,6 +5,7 @@ package edu.cornell.mannlib.vitro.webapp.dao.jena;
|
||||||
import javax.servlet.ServletContext;
|
import javax.servlet.ServletContext;
|
||||||
|
|
||||||
import com.hp.hpl.jena.ontology.OntModel;
|
import com.hp.hpl.jena.ontology.OntModel;
|
||||||
|
import com.hp.hpl.jena.rdf.model.ModelChangedListener;
|
||||||
|
|
||||||
public class ModelContext {
|
public class ModelContext {
|
||||||
|
|
||||||
|
@ -75,4 +76,26 @@ public class ModelContext {
|
||||||
ctx.setAttribute(INFERENCE_ONT_MODEL, ontModel);
|
ctx.setAttribute(INFERENCE_ONT_MODEL, ontModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a listener to the models needed to get changes to:
|
||||||
|
* class membership
|
||||||
|
* inferred class membership
|
||||||
|
* class group membership,
|
||||||
|
* object properties,
|
||||||
|
* data properties,
|
||||||
|
* inferred object properties,
|
||||||
|
* rdfs:label annotations
|
||||||
|
* This listener does not need:
|
||||||
|
* other annotations
|
||||||
|
* change to TBox
|
||||||
|
*/
|
||||||
|
public static void registerListenerForChanges(ServletContext ctx, ModelChangedListener ml){
|
||||||
|
ModelContext.getJenaOntModel(ctx).register(ml);
|
||||||
|
ModelContext.getBaseOntModel(ctx).register(ml);
|
||||||
|
ModelContext.getInferenceOntModel(ctx).register(ml);
|
||||||
|
ModelContext.getUnionOntModelSelector(ctx).getABoxModel().register(ml);
|
||||||
|
ModelContext.getBaseOntModelSelector(ctx).getABoxModel().register(ml);
|
||||||
|
ModelContext.getInferenceOntModelSelector(ctx).getABoxModel().register(ml);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,7 @@
|
||||||
|
|
||||||
package edu.cornell.mannlib.vitro.webapp.dao.jena;
|
package edu.cornell.mannlib.vitro.webapp.dao.jena;
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
@ -34,16 +32,32 @@ public class SearchReindexingListener implements ModelChangedListener {
|
||||||
|
|
||||||
private synchronized void addChange(Statement stmt){
|
private synchronized void addChange(Statement stmt){
|
||||||
if( stmt == null ) return;
|
if( stmt == null ) return;
|
||||||
|
if( log.isDebugEnabled() ){
|
||||||
|
String sub="unknown";
|
||||||
|
String pred = "unknown";
|
||||||
|
String obj ="unknown";
|
||||||
|
|
||||||
|
if( stmt.getSubject().isURIResource() ){
|
||||||
|
sub = stmt.getSubject().getURI();
|
||||||
|
}
|
||||||
|
if( stmt.getPredicate() != null ){
|
||||||
|
pred = stmt.getPredicate().getURI();
|
||||||
|
}
|
||||||
|
if( stmt.getObject().isURIResource() ){
|
||||||
|
obj = ((Resource) (stmt.getPredicate().as(Resource.class))).getURI();
|
||||||
|
}else{
|
||||||
|
obj = stmt.getObject().toString();
|
||||||
|
}
|
||||||
|
log.debug("changed statement: sub='" + sub + "' pred='" + pred +"' obj='" + obj + "'");
|
||||||
|
}
|
||||||
|
|
||||||
if( stmt.getSubject().isURIResource() ){
|
if( stmt.getSubject().isURIResource() ){
|
||||||
//changedUris.add( stmt.getSubject().getURI());
|
|
||||||
indexBuilder.addToChangedUris(stmt.getSubject().getURI());
|
indexBuilder.addToChangedUris(stmt.getSubject().getURI());
|
||||||
log.debug("subject: " + stmt.getSubject().getURI());
|
log.debug("subject: " + stmt.getSubject().getURI());
|
||||||
}
|
}
|
||||||
|
|
||||||
if( stmt.getObject().isURIResource() ){
|
if( stmt.getObject().isURIResource() ){
|
||||||
//changedUris.add( ((Resource) stmt.getObject().as(Resource.class)).getURI() );
|
|
||||||
indexBuilder.addToChangedUris(((Resource) stmt.getObject()).getURI());
|
indexBuilder.addToChangedUris(((Resource) stmt.getObject()).getURI());
|
||||||
log.debug("object: " + ((Resource) stmt.getObject().as(Resource.class)).getURI());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,12 +70,14 @@ public class VClassGroupCache{
|
||||||
}
|
}
|
||||||
|
|
||||||
VClassGroupCacheChangeListener bccl = new VClassGroupCacheChangeListener(this);
|
VClassGroupCacheChangeListener bccl = new VClassGroupCacheChangeListener(this);
|
||||||
ModelContext.getJenaOntModel(context).register(bccl);
|
ModelContext.registerListenerForChanges(context, bccl);
|
||||||
ModelContext.getBaseOntModel(context).register(bccl);
|
//
|
||||||
ModelContext.getInferenceOntModel(context).register(bccl);
|
// ModelContext.getJenaOntModel(context).register(bccl);
|
||||||
ModelContext.getUnionOntModelSelector(context).getABoxModel().register(bccl);
|
// ModelContext.getBaseOntModel(context).register(bccl);
|
||||||
ModelContext.getBaseOntModelSelector(context).getABoxModel().register(bccl);
|
// ModelContext.getInferenceOntModel(context).register(bccl);
|
||||||
ModelContext.getInferenceOntModelSelector(context).getABoxModel().register(bccl);
|
// ModelContext.getUnionOntModelSelector(context).getABoxModel().register(bccl);
|
||||||
|
// ModelContext.getBaseOntModelSelector(context).getABoxModel().register(bccl);
|
||||||
|
// ModelContext.getInferenceOntModelSelector(context).getABoxModel().register(bccl);
|
||||||
|
|
||||||
_rebuildQueue.add(REBUILD_EVERY_PORTAL);
|
_rebuildQueue.add(REBUILD_EVERY_PORTAL);
|
||||||
_cacheRebuildThread = new RebuildGroupCacheThread(this);
|
_cacheRebuildThread = new RebuildGroupCacheThread(this);
|
||||||
|
|
|
@ -26,38 +26,31 @@ import edu.cornell.mannlib.vitro.webapp.search.beans.ProhibitedFromSearch;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The IndexBuilder is used to rebuild or update a search index.
|
* The IndexBuilder is used to rebuild or update a search index.
|
||||||
|
* There should only be one IndexBuilder in a vitro web application.
|
||||||
* It uses an implementation of a back-end through an object that
|
* It uses an implementation of a back-end through an object that
|
||||||
* implements IndexerIface. An example of a back-end is LuceneIndexer.
|
* implements IndexerIface. An example of a back-end is LuceneIndexer.
|
||||||
*
|
*
|
||||||
* See the class SearchReindexingListener for an example of how a model change
|
* See the class SearchReindexingListener for an example of how a model change
|
||||||
* listener can use an IndexBuilder to keep the full text index in sncy with
|
* listener can use an IndexBuilder to keep the full text index in sncy with
|
||||||
* updates to a model.
|
* updates to a model. It calls IndexBuilder.addToChangedUris().
|
||||||
*
|
*
|
||||||
* There should be an IndexBuilder in the servlet context, try:
|
|
||||||
*
|
|
||||||
IndexBuilder builder = (IndexBuilder)getServletContext().getAttribute(IndexBuilder.class.getName());
|
|
||||||
if( request.getParameter("update") != null )
|
|
||||||
builder.doUpdateIndex();
|
|
||||||
|
|
||||||
* @author bdc34
|
* @author bdc34
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class IndexBuilder {
|
public class IndexBuilder extends Thread {
|
||||||
private List<ObjectSourceIface> sourceList = new LinkedList<ObjectSourceIface>();
|
private List<ObjectSourceIface> sourceList = new LinkedList<ObjectSourceIface>();
|
||||||
private IndexerIface indexer = null;
|
private IndexerIface indexer = null;
|
||||||
private ServletContext context = null;
|
private ServletContext context = null;
|
||||||
|
|
||||||
private long lastRun = 0;
|
/* changedUris should only be accessed from synchronized blocks */
|
||||||
|
|
||||||
private HashSet<String> changedUris = null;
|
private HashSet<String> changedUris = null;
|
||||||
|
|
||||||
private List<Individual> updatedInds = null;
|
private List<Individual> updatedInds = null;
|
||||||
private List<Individual> deletedInds = null;
|
private List<Individual> deletedInds = null;
|
||||||
|
|
||||||
private IndexBuilderThread indexingThread = null;
|
|
||||||
|
|
||||||
//shared with IndexBuilderThread
|
|
||||||
private boolean reindexRequested = false;
|
private boolean reindexRequested = false;
|
||||||
|
protected boolean stopRequested = false;
|
||||||
|
protected long reindexInterval = 1000 * 60 /* msec */ ;
|
||||||
|
|
||||||
public static final boolean UPDATE_DOCS = false;
|
public static final boolean UPDATE_DOCS = false;
|
||||||
public static final boolean NEW_DOCS = true;
|
public static final boolean NEW_DOCS = true;
|
||||||
|
@ -67,13 +60,18 @@ public class IndexBuilder {
|
||||||
public IndexBuilder(ServletContext context,
|
public IndexBuilder(ServletContext context,
|
||||||
IndexerIface indexer,
|
IndexerIface indexer,
|
||||||
List /*ObjectSourceIface*/ sources){
|
List /*ObjectSourceIface*/ sources){
|
||||||
|
super("IndexBuilder");
|
||||||
this.indexer = indexer;
|
this.indexer = indexer;
|
||||||
this.sourceList = sources;
|
this.sourceList = sources;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
|
||||||
this.changedUris = new HashSet<String>();
|
this.changedUris = new HashSet<String>();
|
||||||
this.indexingThread = new IndexBuilderThread(this);
|
this.start();
|
||||||
this.indexingThread.start();
|
}
|
||||||
|
|
||||||
|
protected IndexBuilder(){
|
||||||
|
//for testing only
|
||||||
|
this( null, null, Collections.emptyList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addObjectSource(ObjectSourceIface osi) {
|
public void addObjectSource(ObjectSourceIface osi) {
|
||||||
|
@ -89,24 +87,20 @@ public class IndexBuilder {
|
||||||
return sourceList;
|
return sourceList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void doIndexRebuild() throws IndexingException {
|
public synchronized void doIndexRebuild() throws IndexingException {
|
||||||
//set up full index rebuild
|
//set flag for full index rebuild
|
||||||
setReindexRequested( true );
|
this.reindexRequested = true;
|
||||||
//wake up indexing thread
|
//wake up
|
||||||
synchronized (this.indexingThread) {
|
this.notifyAll();
|
||||||
this.indexingThread.notifyAll();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This will re-index Individuals that changed because of modtime or because they
|
* This will re-index Individuals that changed because of modtime or because they
|
||||||
* were added with addChangedUris().
|
* were added with addChangedUris().
|
||||||
*/
|
*/
|
||||||
public void doUpdateIndex() {
|
public synchronized void doUpdateIndex() {
|
||||||
//wake up thread
|
//wake up thread and it will attempt to index anything in changedUris
|
||||||
synchronized (this.indexingThread) {
|
this.notifyAll();
|
||||||
this.indexingThread.notifyAll();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void addToChangedUris(String uri){
|
public synchronized void addToChangedUris(String uri){
|
||||||
|
@ -125,79 +119,47 @@ public class IndexBuilder {
|
||||||
return isReindexRequested() || ! changedUris.isEmpty() ;
|
return isReindexRequested() || ! changedUris.isEmpty() ;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void killIndexingThread() {
|
public synchronized void stopIndexingThread() {
|
||||||
this.indexingThread.kill();
|
stopRequested = true;
|
||||||
|
this.notifyAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while(! stopRequested ){
|
||||||
|
try{
|
||||||
|
if( !stopRequested && isReindexRequested() ){
|
||||||
|
log.debug("full re-index requested");
|
||||||
|
indexRebuild();
|
||||||
|
}else if( !stopRequested && isThereWorkToDo() ){
|
||||||
|
Thread.sleep(250); //wait a bit to let a bit more work to come into the queue
|
||||||
|
log.debug("work found for IndexBuilder, starting update");
|
||||||
|
updatedIndex();
|
||||||
|
}else if( !stopRequested && ! isThereWorkToDo() ){
|
||||||
|
log.debug("there is no indexing working to do, waiting for work");
|
||||||
|
synchronized (this) { this.wait(reindexInterval); }
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
log.debug("woken up",e);
|
||||||
|
}catch(Throwable e){
|
||||||
|
log.error(e,e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.info("Stopping IndexBuilder thread");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ******************** non-public methods ************************* */
|
/* ******************** non-public methods ************************* */
|
||||||
|
|
||||||
private synchronized void setReindexRequested(boolean reindexRequested) {
|
|
||||||
this.reindexRequested = reindexRequested;
|
|
||||||
}
|
|
||||||
|
|
||||||
private synchronized Collection<String> getAndEmptyChangedUris(){
|
private synchronized Collection<String> getAndEmptyChangedUris(){
|
||||||
Collection<String> out = changedUris;
|
Collection<String> out = changedUris;
|
||||||
changedUris = new HashSet<String>();
|
changedUris = new HashSet<String>();
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void indexRebuild() throws IndexingException {
|
|
||||||
log.info("Rebuild of search index is starting.");
|
|
||||||
|
|
||||||
Iterator<ObjectSourceIface> sources = sourceList.iterator();
|
|
||||||
List listOfIterators = new LinkedList();
|
|
||||||
while(sources.hasNext()){
|
|
||||||
Object obj = sources.next();
|
|
||||||
if( obj != null && obj instanceof ObjectSourceIface )
|
|
||||||
listOfIterators.add((((ObjectSourceIface) obj)
|
|
||||||
.getAllOfThisTypeIterator()));
|
|
||||||
else
|
|
||||||
log.warn("\tskipping object of class "
|
|
||||||
+ obj.getClass().getName() + "\n"
|
|
||||||
+ "\tIt doesn not implement ObjectSourceIface.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
//clear out changed uris since we are doing a full index rebuild
|
|
||||||
getAndEmptyChangedUris();
|
|
||||||
|
|
||||||
if( listOfIterators.size() == 0){ log.warn("Warning: no ObjectSources found.");}
|
|
||||||
|
|
||||||
setReindexRequested(false);
|
|
||||||
doBuild( listOfIterators, Collections.EMPTY_LIST, true, NEW_DOCS );
|
|
||||||
log.info("Rebuild of search index is complete.");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void updatedIndex() throws IndexingException{
|
|
||||||
log.debug("Starting updateIndex()");
|
|
||||||
long since = indexer.getModified() - 60000;
|
|
||||||
|
|
||||||
Iterator<ObjectSourceIface> sources = sourceList.iterator();
|
|
||||||
|
|
||||||
List<Iterator<Individual>> listOfIterators =
|
|
||||||
new LinkedList<Iterator<Individual>>();
|
|
||||||
|
|
||||||
while (sources.hasNext()) {
|
|
||||||
Object obj = sources.next();
|
|
||||||
if (obj != null && obj instanceof ObjectSourceIface)
|
|
||||||
listOfIterators.add((((ObjectSourceIface) obj)
|
|
||||||
.getUpdatedSinceIterator(since)));
|
|
||||||
else
|
|
||||||
log.warn("\tskipping object of class "
|
|
||||||
+ obj.getClass().getName() + "\n"
|
|
||||||
+ "\tIt doesn not implement " + "ObjectSourceIface.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
buildAddAndDeleteLists( getAndEmptyChangedUris());
|
|
||||||
listOfIterators.add( (new IndexBuilder.BuilderObjectSource(updatedInds)).getUpdatedSinceIterator(0) );
|
|
||||||
|
|
||||||
doBuild( listOfIterators, deletedInds, false, UPDATE_DOCS );
|
|
||||||
log.debug("Ending updateIndex()");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets updatedUris and deletedUris.
|
* Sets updatedUris and deletedUris lists.
|
||||||
* @param changedUris
|
|
||||||
*/
|
*/
|
||||||
private void buildAddAndDeleteLists( Collection<String> uris){
|
private void makeAddAndDeleteLists( Collection<String> uris){
|
||||||
/* clear updateInds and deletedUris. This is the only method that should set these. */
|
/* clear updateInds and deletedUris. This is the only method that should set these. */
|
||||||
this.updatedInds = new ArrayList<Individual>();
|
this.updatedInds = new ArrayList<Individual>();
|
||||||
this.deletedInds = new ArrayList<Individual>();
|
this.deletedInds = new ArrayList<Individual>();
|
||||||
|
@ -218,8 +180,160 @@ public class IndexBuilder {
|
||||||
this.updatedInds = addDepResourceClasses(updatedInds);
|
this.updatedInds = addDepResourceClasses(updatedInds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void indexRebuild() throws IndexingException {
|
||||||
|
log.info("Rebuild of search index is starting.");
|
||||||
|
|
||||||
|
Iterator<ObjectSourceIface> sources = sourceList.iterator();
|
||||||
|
List listOfIterators = new LinkedList();
|
||||||
|
while (sources.hasNext()) {
|
||||||
|
Object obj = sources.next();
|
||||||
|
if (obj != null && obj instanceof ObjectSourceIface)
|
||||||
|
listOfIterators.add((((ObjectSourceIface) obj)
|
||||||
|
.getAllOfThisTypeIterator()));
|
||||||
|
else
|
||||||
|
log.warn("\tskipping object of class "
|
||||||
|
+ obj.getClass().getName() + "\n"
|
||||||
|
+ "\tIt doesn not implement ObjectSourceIface.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear out changed uris since we are doing a full index rebuild
|
||||||
|
getAndEmptyChangedUris();
|
||||||
|
|
||||||
|
if (listOfIterators.size() == 0)
|
||||||
|
log.warn("Warning: no ObjectSources found.");
|
||||||
|
|
||||||
|
doBuild(listOfIterators, Collections.EMPTY_LIST );
|
||||||
|
if( log != null ) //log might be null if system is shutting down.
|
||||||
|
log.info("Rebuild of search index is complete.");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void updatedIndex() throws IndexingException{
|
||||||
|
log.debug("Starting updateIndex()");
|
||||||
|
long since = indexer.getModified() - 60000;
|
||||||
|
|
||||||
|
Iterator<ObjectSourceIface> sources = sourceList.iterator();
|
||||||
|
List<Iterator<Individual>> listOfIterators =
|
||||||
|
new LinkedList<Iterator<Individual>>();
|
||||||
|
|
||||||
|
while (sources.hasNext()) {
|
||||||
|
Object obj = sources.next();
|
||||||
|
if (obj != null && obj instanceof ObjectSourceIface)
|
||||||
|
listOfIterators.add((((ObjectSourceIface) obj)
|
||||||
|
.getUpdatedSinceIterator(since)));
|
||||||
|
else
|
||||||
|
log.warn("\tskipping object of class "
|
||||||
|
+ obj.getClass().getName() + "\n"
|
||||||
|
+ "\tIt doesn not implement " + "ObjectSourceIface.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
makeAddAndDeleteLists( getAndEmptyChangedUris());
|
||||||
|
listOfIterators.add( (new IndexBuilder.BuilderObjectSource(updatedInds)).getUpdatedSinceIterator(0) );
|
||||||
|
|
||||||
|
doBuild( listOfIterators, deletedInds );
|
||||||
|
log.debug("Ending updateIndex()");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For each sourceIterator, get all of the objects and attempt to
|
||||||
|
* index them.
|
||||||
|
*
|
||||||
|
* This takes a list of source Iterators and, for each of these,
|
||||||
|
* calls indexForSource.
|
||||||
|
*
|
||||||
|
* @param sourceIterators
|
||||||
|
* @param newDocs true if we know that the document is new. Set
|
||||||
|
* to false if we want to attempt to remove the object from the index before
|
||||||
|
* attempting to index it. If an object is not on the list but you set this
|
||||||
|
* to false, and a check is made before adding, it will work fine; but
|
||||||
|
* checking if an object is on the index is slow.
|
||||||
|
*/
|
||||||
|
private void doBuild(List<Iterator<Individual>> sourceIterators, Collection<Individual> deletes ){
|
||||||
|
boolean aborted = false;
|
||||||
|
boolean newDocs = reindexRequested;
|
||||||
|
boolean forceNewIndex = reindexRequested;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if( reindexRequested )
|
||||||
|
indexer.prepareForRebuild();
|
||||||
|
|
||||||
|
indexer.startIndexing();
|
||||||
|
reindexRequested = false;
|
||||||
|
|
||||||
|
if( ! forceNewIndex ){
|
||||||
|
for(Individual deleteMe : deletes ){
|
||||||
|
indexer.removeFromIndex(deleteMe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//get an iterator for all of the sources of indexable objects
|
||||||
|
Iterator sourceIters = sourceIterators.iterator();
|
||||||
|
Object obj = null;
|
||||||
|
while (sourceIters.hasNext()) {
|
||||||
|
obj = sourceIters.next();
|
||||||
|
if (obj == null || !(obj instanceof Iterator)) {
|
||||||
|
log.warn("skipping object of class " + obj.getClass().getName()
|
||||||
|
+ "It doesn not implement Iterator.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
indexForSource((Iterator)obj, newDocs);
|
||||||
|
}
|
||||||
|
} catch (AbortIndexing abort){
|
||||||
|
if( log != null)
|
||||||
|
log.debug("aborting the indexing because thread stop was requested");
|
||||||
|
aborted = true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e,e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( aborted && forceNewIndex ){
|
||||||
|
indexer.abortIndexingAndCleanUp();
|
||||||
|
}else{
|
||||||
|
indexer.endIndexing();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use the back end indexer to index each object that the Iterator returns.
|
||||||
|
* @throws AbortIndexing
|
||||||
|
*/
|
||||||
|
private void indexForSource(Iterator<Individual> individuals , boolean newDocs) throws AbortIndexing{
|
||||||
|
long starttime = System.currentTimeMillis();
|
||||||
|
long count = 0;
|
||||||
|
while(individuals.hasNext()){
|
||||||
|
if( stopRequested )
|
||||||
|
throw new AbortIndexing();
|
||||||
|
|
||||||
|
Individual ind = null;
|
||||||
|
try{
|
||||||
|
ind = individuals.next();
|
||||||
|
indexer.index(ind, newDocs);
|
||||||
|
}catch(Throwable ex){
|
||||||
|
if( stopRequested || log == null){//log might be null if system is shutting down.
|
||||||
|
throw new AbortIndexing();
|
||||||
|
}
|
||||||
|
String uri = ind!=null?ind.getURI():"null";
|
||||||
|
log.warn("Error indexing individual " + uri + " " + ex.getMessage());
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
if( log.isDebugEnabled() ){
|
||||||
|
if( (count % 100 ) == 0 && count > 0 ){
|
||||||
|
long dt = (System.currentTimeMillis() - starttime);
|
||||||
|
log.debug("individuals indexed: " + count + " in " + dt + " msec " +
|
||||||
|
" time pre individual = " + (dt / count) + " msec" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info(
|
||||||
|
"individuals indexed: " + count + " in " + (System.currentTimeMillis() - starttime) + " msec" +
|
||||||
|
(count!=0?(" time per individual = " + (System.currentTimeMillis() - starttime)/ count + " msec"):"")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For a list of individuals, this builds a list of dependent resources and returns it.
|
||||||
|
*/
|
||||||
private List<Individual> addDepResourceClasses(List<Individual> inds) {
|
private List<Individual> addDepResourceClasses(List<Individual> inds) {
|
||||||
WebappDaoFactory wdf = (WebappDaoFactory)context.getAttribute("webappDaoFactory");
|
WebappDaoFactory wdf = (WebappDaoFactory)context.getAttribute("webappDaoFactory");
|
||||||
VClassDao vClassDao = wdf.getVClassDao();
|
VClassDao vClassDao = wdf.getVClassDao();
|
||||||
|
@ -256,107 +370,12 @@ public class IndexBuilder {
|
||||||
return inds;
|
return inds;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/* maybe ObjectSourceIface should be replaced with just an iterator. */
|
||||||
* For each sourceIterator, get all of the objects and attempt to
|
|
||||||
* index them.
|
|
||||||
*
|
|
||||||
* This takes a list of source Iterators and, for each of these,
|
|
||||||
* calls indexForSource.
|
|
||||||
*
|
|
||||||
* @param sourceIterators
|
|
||||||
* @param newDocs true if we know that the document is new. Set
|
|
||||||
* to false if we want to attempt to remove the object from the index before
|
|
||||||
* attempting to index it. If an object is not on the list but you set this
|
|
||||||
* to false, and a check is made before adding, it will work fine; but
|
|
||||||
* checking if an object is on the index is slow.
|
|
||||||
*/
|
|
||||||
private void doBuild(List sourceIterators, Collection<Individual> deletes, boolean forceNewIndex, boolean newDocs ){
|
|
||||||
try {
|
|
||||||
if( forceNewIndex )
|
|
||||||
indexer.prepareForRebuild();
|
|
||||||
|
|
||||||
indexer.startIndexing();
|
|
||||||
|
|
||||||
if( ! forceNewIndex ){
|
|
||||||
for(Individual deleteMe : deletes ){
|
|
||||||
indexer.removeFromIndex(deleteMe);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//get an iterator for all of the sources of indexable objects
|
|
||||||
Iterator sourceIters = sourceIterators.iterator();
|
|
||||||
Object obj = null;
|
|
||||||
while (sourceIters.hasNext()) {
|
|
||||||
obj = sourceIters.next();
|
|
||||||
if (obj == null || !(obj instanceof Iterator)) {
|
|
||||||
log.warn("\tskipping object of class "
|
|
||||||
+ obj.getClass().getName() + "\n"
|
|
||||||
+ "\tIt doesn not implement "
|
|
||||||
+ "Iterator.\n");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
indexForSource((Iterator)obj, newDocs);
|
|
||||||
}
|
|
||||||
} catch (IndexingException ex) {
|
|
||||||
log.error(ex,ex);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error(e,e);
|
|
||||||
} finally {
|
|
||||||
indexer.endIndexing();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use the back end indexer to index each object that the Iterator returns.
|
|
||||||
* @param items
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private void indexForSource(Iterator<Individual> individuals , boolean newDocs){
|
|
||||||
if( individuals == null ) return;
|
|
||||||
|
|
||||||
long starttime = System.currentTimeMillis();
|
|
||||||
long count = 0;
|
|
||||||
while(individuals.hasNext()){
|
|
||||||
indexItem(individuals.next(), newDocs);
|
|
||||||
count++;
|
|
||||||
if( log.isDebugEnabled() ){
|
|
||||||
if( (count % 100 ) == 0 && count > 0 ){
|
|
||||||
long dt = (System.currentTimeMillis() - starttime);
|
|
||||||
log.debug("individuals indexed: " + count + " in " + dt + " msec " +
|
|
||||||
" time pre individual = " + (dt / count) + " msec" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info(
|
|
||||||
"individuals indexed: " + count + " in " + (System.currentTimeMillis() - starttime) + " msec" +
|
|
||||||
(count!=0?(" time per individual = " + (System.currentTimeMillis() - starttime)/ count + " msec"):"")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use the backend indexer to index a single item.
|
|
||||||
* @param item
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private void indexItem( Individual ind, boolean newDoc){
|
|
||||||
try{
|
|
||||||
if( ind != null ){
|
|
||||||
indexer.index(ind, newDoc);
|
|
||||||
}
|
|
||||||
}catch(Throwable ex){
|
|
||||||
log.warn("IndexBuilder.indexItem() Error indexing "
|
|
||||||
+ ind + "\n" +ex);
|
|
||||||
}
|
|
||||||
return ;
|
|
||||||
}
|
|
||||||
|
|
||||||
private class BuilderObjectSource implements ObjectSourceIface {
|
private class BuilderObjectSource implements ObjectSourceIface {
|
||||||
private final List<Individual> individuals;
|
private final List<Individual> individuals;
|
||||||
public BuilderObjectSource( List<Individual> individuals){
|
public BuilderObjectSource( List<Individual> individuals){
|
||||||
this.individuals=individuals;
|
this.individuals=individuals;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Iterator getAllOfThisTypeIterator() {
|
public Iterator getAllOfThisTypeIterator() {
|
||||||
return new Iterator(){
|
return new Iterator(){
|
||||||
final Iterator it = individuals.iterator();
|
final Iterator it = individuals.iterator();
|
||||||
|
@ -372,13 +391,10 @@ public class IndexBuilder {
|
||||||
public void remove() { /* not implemented */}
|
public void remove() { /* not implemented */}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public Iterator getUpdatedSinceIterator(long msSinceEpoc) {
|
public Iterator getUpdatedSinceIterator(long msSinceEpoc) {
|
||||||
return getAllOfThisTypeIterator();
|
return getAllOfThisTypeIterator();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class AbortIndexing extends Exception { }
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,72 +0,0 @@
|
||||||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
|
||||||
|
|
||||||
package edu.cornell.mannlib.vitro.webapp.search.indexing;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Thread that executes the methods in IndexBuilder.
|
|
||||||
*
|
|
||||||
* @author bdc34
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class IndexBuilderThread extends Thread{
|
|
||||||
private IndexBuilder indexBuilder;
|
|
||||||
protected boolean stopRequested = false;
|
|
||||||
protected long reindexInterval = 1000 * 60 /* msec */ ;
|
|
||||||
|
|
||||||
private static final Log log = LogFactory.getLog(IndexBuilderThread.class.getName());
|
|
||||||
|
|
||||||
public IndexBuilderThread(IndexBuilder ib){
|
|
||||||
super("IndexBuilderThread");
|
|
||||||
if( ib == null )
|
|
||||||
log.error("IndexBuilderThread needs an IndexBuilder, search is not configured.");
|
|
||||||
this.indexBuilder = ib;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
while(true){
|
|
||||||
if( stopRequested ){
|
|
||||||
log.info("Stopping IndexBuilderThread ");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( indexBuilder == null )
|
|
||||||
log.warn("IndexBuilderThread needs a IndexBuilder, search may not be configured.");
|
|
||||||
|
|
||||||
try{
|
|
||||||
if( indexBuilder != null && indexBuilder.isReindexRequested() ){
|
|
||||||
log.debug("full re-index requested");
|
|
||||||
indexBuilder.indexRebuild();
|
|
||||||
}else{
|
|
||||||
if( indexBuilder != null && indexBuilder.isThereWorkToDo() ){
|
|
||||||
Thread.sleep(250); //wait a bit to let a bit more work to come into the queue
|
|
||||||
log.debug("work found for IndexBuilder, starting update");
|
|
||||||
indexBuilder.updatedIndex();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}catch (Throwable e) {
|
|
||||||
log.error(e,e);
|
|
||||||
}
|
|
||||||
|
|
||||||
if( indexBuilder != null && ! indexBuilder.isThereWorkToDo() ){
|
|
||||||
log.debug("there is no indexing working to do, going to sleep");
|
|
||||||
try {
|
|
||||||
synchronized (this) {
|
|
||||||
this.wait(reindexInterval);
|
|
||||||
}
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
log.debug(" woken up",e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void kill(){
|
|
||||||
log.debug("Attempting to kill IndexBuilderThread ");
|
|
||||||
stopRequested = true;
|
|
||||||
this.notifyAll();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -54,4 +54,10 @@ public interface IndexerIface {
|
||||||
public void endIndexing();
|
public void endIndexing();
|
||||||
|
|
||||||
public long getModified();
|
public long getModified();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ends the indexing and removes any temporary files.
|
||||||
|
* This may be called instead of endIndexing()
|
||||||
|
*/
|
||||||
|
public void abortIndexingAndCleanUp();
|
||||||
}
|
}
|
||||||
|
|
|
@ -456,4 +456,21 @@ public class LuceneIndexer implements IndexerIface {
|
||||||
//if it is clear it out but don't rebuild.
|
//if it is clear it out but don't rebuild.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void abortIndexingAndCleanUp() {
|
||||||
|
if( ! indexing )
|
||||||
|
log.error("abortIndexingAndCleanUp() should only be called if LuceneIndexer is indexing.");
|
||||||
|
else if( ! fullRebuild )
|
||||||
|
log.error("abortIndexingAndCleanUp() should only be called if LuceneIndexer to end an aborted full index rebuild");
|
||||||
|
else{
|
||||||
|
closeWriter();
|
||||||
|
File offLineDir = new File(currentOffLineDir);
|
||||||
|
boolean deleted = deleteDir(offLineDir);
|
||||||
|
//log might be null if system is shutting down.
|
||||||
|
if( ! deleted ){
|
||||||
|
System.out.println("Could not clean up temp indexing dir " + currentOffLineDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,17 +134,12 @@ public class LuceneSetup implements javax.servlet.ServletContextListener {
|
||||||
// set up listeners so search index builder is notified of changes to model
|
// set up listeners so search index builder is notified of changes to model
|
||||||
ServletContext ctx = sce.getServletContext();
|
ServletContext ctx = sce.getServletContext();
|
||||||
SearchReindexingListener srl = new SearchReindexingListener(builder);
|
SearchReindexingListener srl = new SearchReindexingListener(builder);
|
||||||
ModelContext.getBaseOntModel(ctx).getBaseModel().register(srl);
|
ModelContext.registerListenerForChanges(ctx, srl);
|
||||||
ModelContext.getJenaOntModel(ctx).getBaseModel().register(srl);
|
|
||||||
ModelContext.getInferenceOntModel(ctx).register(srl);
|
|
||||||
ModelContext.getUnionOntModelSelector(ctx).getABoxModel()
|
|
||||||
.getBaseModel().register(srl);
|
|
||||||
|
|
||||||
if( (Boolean)sce.getServletContext().getAttribute(INDEX_REBUILD_REQUESTED_AT_STARTUP) instanceof Boolean &&
|
if( (Boolean)sce.getServletContext().getAttribute(INDEX_REBUILD_REQUESTED_AT_STARTUP) instanceof Boolean &&
|
||||||
(Boolean)sce.getServletContext().getAttribute(INDEX_REBUILD_REQUESTED_AT_STARTUP) ){
|
(Boolean)sce.getServletContext().getAttribute(INDEX_REBUILD_REQUESTED_AT_STARTUP) ){
|
||||||
log.info("Rebuild of lucene index required before startup.");
|
log.info("Rebuild of lucene index required before startup.");
|
||||||
builder.doIndexRebuild();
|
builder.doIndexRebuild();
|
||||||
Thread.currentThread().sleep(500);
|
|
||||||
int n = 0;
|
int n = 0;
|
||||||
while( builder.isReindexRequested() || builder.isIndexing() ){
|
while( builder.isReindexRequested() || builder.isIndexing() ){
|
||||||
n++;
|
n++;
|
||||||
|
@ -169,7 +164,7 @@ public class LuceneSetup implements javax.servlet.ServletContextListener {
|
||||||
log.debug("**** Running " + this.getClass().getName() + ".contextDestroyed()");
|
log.debug("**** Running " + this.getClass().getName() + ".contextDestroyed()");
|
||||||
IndexBuilder builder = (IndexBuilder) sce.getServletContext().getAttribute(IndexBuilder.class.getName());
|
IndexBuilder builder = (IndexBuilder) sce.getServletContext().getAttribute(IndexBuilder.class.getName());
|
||||||
if( builder != null){
|
if( builder != null){
|
||||||
builder.killIndexingThread();
|
builder.stopIndexingThread();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,8 +25,8 @@ import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
|
||||||
import edu.cornell.mannlib.vitro.webapp.dao.filtering.WebappDaoFactoryFiltering;
|
import edu.cornell.mannlib.vitro.webapp.dao.filtering.WebappDaoFactoryFiltering;
|
||||||
import edu.cornell.mannlib.vitro.webapp.dao.filtering.filters.VitroFilterUtils;
|
import edu.cornell.mannlib.vitro.webapp.dao.filtering.filters.VitroFilterUtils;
|
||||||
import edu.cornell.mannlib.vitro.webapp.dao.filtering.filters.VitroFilters;
|
import edu.cornell.mannlib.vitro.webapp.dao.filtering.filters.VitroFilters;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.dao.jena.ModelContext;
|
||||||
import edu.cornell.mannlib.vitro.webapp.dao.jena.SearchReindexingListener;
|
import edu.cornell.mannlib.vitro.webapp.dao.jena.SearchReindexingListener;
|
||||||
import edu.cornell.mannlib.vitro.webapp.search.beans.Searcher;
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.search.indexing.IndexBuilder;
|
import edu.cornell.mannlib.vitro.webapp.search.indexing.IndexBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -108,8 +108,7 @@ public class LuceneSetupCJK implements javax.servlet.ServletContextListener {
|
||||||
OntModel baseOntModel = (OntModel)sce.getServletContext().getAttribute("baseOntModel");
|
OntModel baseOntModel = (OntModel)sce.getServletContext().getAttribute("baseOntModel");
|
||||||
OntModel jenaOntModel = (OntModel)sce.getServletContext().getAttribute("jenaOntModel");
|
OntModel jenaOntModel = (OntModel)sce.getServletContext().getAttribute("jenaOntModel");
|
||||||
SearchReindexingListener srl = new SearchReindexingListener( builder );
|
SearchReindexingListener srl = new SearchReindexingListener( builder );
|
||||||
baseOntModel.getBaseModel().register(srl);
|
ModelContext.registerListenerForChanges(sce.getServletContext(), srl);
|
||||||
jenaOntModel.getBaseModel().register(srl);
|
|
||||||
|
|
||||||
}catch(Exception ex){
|
}catch(Exception ex){
|
||||||
log.error("Could not setup lucene full text search." , ex);
|
log.error("Could not setup lucene full text search." , ex);
|
||||||
|
@ -125,7 +124,7 @@ public class LuceneSetupCJK implements javax.servlet.ServletContextListener {
|
||||||
|
|
||||||
log.info("**** Running "+this.getClass().getName()+".contextDestroyed()");
|
log.info("**** Running "+this.getClass().getName()+".contextDestroyed()");
|
||||||
IndexBuilder builder = (IndexBuilder)sce.getServletContext().getAttribute(IndexBuilder.class.getName());
|
IndexBuilder builder = (IndexBuilder)sce.getServletContext().getAttribute(IndexBuilder.class.getName());
|
||||||
builder.killIndexingThread();
|
builder.stopIndexingThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -14,20 +14,24 @@ public class IndexBuilderThreadTest extends AbstractTestClass {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testStoppingTheThread(){
|
public void testStoppingTheThread(){
|
||||||
setLoggerLevel(IndexBuilderThread.class, Level.OFF);
|
setLoggerLevel(IndexBuilder.class, Level.OFF);
|
||||||
IndexBuilderThread ibt = new IndexBuilderThread(null);
|
|
||||||
ibt.start();
|
IndexBuilder ib = new IndexBuilder();
|
||||||
|
Assert.assertNotSame(Thread.State.NEW, ib.getState() );
|
||||||
|
Assert.assertNotSame(Thread.State.TERMINATED, ib.getState() );
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Thread.sleep(100);
|
Thread.sleep(100);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Assert.fail(e.getMessage());
|
Assert.fail(e.getMessage());
|
||||||
}
|
}
|
||||||
ibt.kill();
|
ib.stopIndexingThread();
|
||||||
try {
|
try {
|
||||||
Thread.sleep(100);
|
Thread.sleep(100);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Assert.fail(e.getMessage());
|
Assert.fail(e.getMessage());
|
||||||
}
|
}
|
||||||
Assert.assertFalse(ibt.isAlive());
|
Assert.assertFalse(ib.isAlive());
|
||||||
|
Assert.assertSame(Thread.State.TERMINATED, ib.getState() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue