public class Solrindexer implements Indexer, Searcher, Disposablebean {
~ Static fields/initializers =============================================
static final Logger Logger = Loggerfactory.getlogger (Solrindexer.class);
private static final Long shutdown_timeout = 5 * 1000L;//long enough
p Rivate static final int input_queue_length = 16384;
//~ Instance fields ========================================================
private Commonshttpsolrserver server;
private blockingqueue<operation> inputqueue;
private Thread Updatethread;
volatile Boolean running = true;
volatile Boolean shuttingdown = false;
//~ Constructors ===========================================================
Public solrindexer (String URL) throws Malformedurlexception {
Server = new Commonshttpsolrserver (URL);
Inputqueue = new arrayblockingqueue<operation> (input_queue_length);
Updatethread = new Thread (new Updatetask ());
Updatethread.setname ("Solrindexer");
Updatethread.start ();
}
~ Methods ================================================================
public void setsotimeout (int timeout) {
Server.setsotimeout (timeout);
}
public void setconnectiontimeout (int timeout) {
Server.setconnectiontimeout (timeout);
}
public void Setallowcompression (Boolean allowcompression) {
Server.setallowcompression (allowcompression);
}
public void Addindex (indexable indexable) throws Indexingexception {
if (Shuttingdown) {
throw new IllegalStateException ("Solrindexer is shutting down");
}
Inputqueue.offer (New Operation (indexable, operationtype.update));
}
public void Delindex (indexable indexable) throws Indexingexception {
if (Shuttingdown) {
throw new IllegalStateException ("Solrindexer is shutting down");
}
Inputqueue.offer (New Operation (indexable, operationtype.delete));
}
private void Updateindices (String type, list<indexable> indices) throws Indexingexception {
if (indices = NULL | | indices.size () = 0) {
Return
}
Logger.debug ("Updating {} indices", indices.size ());
Updaterequest req = new Updaterequest ("/" + type + "/update");
Req.setaction (UpdateRequest.ACTION.COMMIT, False, false);
for (indexable idx:indices) {
Doc doc = Idx.getdoc ();
Solrinputdocument Solrdoc = new Solrinputdocument ();
Solrdoc.setdocumentboost (Doc.getdocumentboost ());
for (Iterator<field> i = Doc.iterator (); I.hasnext ();) {
Field field = I.next ();
Solrdoc.addfield (Field.getname (), Field.getvalue (), Field.getboost ());
}
Req.add (Solrdoc);
}
try {
Req.process (server);
catch (Solrserverexception e) {
Logger.error ("Solrserverexception occurred", e);
throw new Indexingexception (e);
catch (IOException e) {
Logger.error ("IOException occurred", e);
throw new Indexingexception (e);
}
}
private void Delindices (String type, list<indexable> indices) throws Indexingexception {
if (indices = NULL | | indices.size () = 0) {
Return
}
Logger.debug ("Deleting {} indices", indices.size ());
Updaterequest req = new Updaterequest ("/" + type + "/update");
Req.setaction (UpdateRequest.ACTION.COMMIT, False, false);
for (indexable indexable:indices) {
Req.deletebyid (Indexable.getdocid ());
}
try {
Req.process (server);
catch (Solrserverexception e) {
Logger.error ("Solrserverexception occurred", e);
throw new Indexingexception (e);
catch (IOException e) {
Logger.error ("IOException occurred", e);
throw new Indexingexception (e);
}
}
Public QueryResult Search (query query) throws Indexingexception {
solrquery sq = new solrquery ();
Sq.setquery (Query.getquery ());
if (query.getfilter ()!= null) {
Sq.addfilterquery (Query.getfilter ());
}
if (Query.getorderfield ()!= null) {
Sq.addsortfield (Query.getorderfield (), query.getorder () = = Query.Order.DESC? SOLRQUERY.ORDER.DESC:SOLRQUERY.ORDER.ASC);
}
Sq.setstart (Query.getoffset ());
Sq.setrows (Query.getlimit ());
Queryrequest req = new Queryrequest (sq);
Req.setpath ("/" + query.gettype () + "/select");
try {
Queryresponse RSP = req.process (server);
Solrdocumentlist docs = Rsp.getresults ();
QueryResult result = new QueryResult ();
Result.setoffset (Docs.getstart ());
Result.settotal (Docs.getnumfound ());
Result.setsize (Sq.getrows ());
list<doc> Resultdocs = new arraylist<doc> (Result.getsize ());
for (Iterator<solrdocument> i = Docs.iterator (); I.hasnext ();) {
Solrdocument solrdocument = I.next ();
Doc doc = new doc ();
For (iterator<map.entry<string, object>> iter = Solrdocument.iterator (); Iter.hasnext ();) {
map.entry<string, object> field = Iter.next ();
Doc.addfield (Field.getkey (), Field.getvalue ());
}
Resultdocs.add (DOC);
}
Result.setdocs (Resultdocs);
return result;
catch (Solrserverexception e) {
Logger.error ("Solrserverexception occurred", e);
throw new Indexingexception (e);
}
}
public void Destroy () throws Exception {
Shutdown (shutdown_timeout, timeunit.milliseconds);
}
Public boolean shutdown (long timeout, timeunit) {
if (Shuttingdown) {
Logger.info ("Suppressing duplicate attempt to shut down");
return false;
}
Shuttingdown = true;
String baseName = Updatethread.getname ();
Updatethread.setname (BaseName + "-shutting down");
Boolean RV = false;
try {
Conditionally wait
if (Timeout > 0) {
Updatethread.setname (BaseName + "-Shutting down (waiting)");
RV = Waitforqueue (timeout, unit);
}
finally {
But always begin the shutdown sequence
running = false;
Updatethread.setname (BaseName + "-Shutting down (informed client)");
}
return RV;
}
/**
* @param timeout
* @param unit
* @return
*/
Private Boolean Waitforqueue (long timeout, timeunit unit) {
Countdownlatch latch = new Countdownlatch (1);
Inputqueue.add (new stopoperation (latch));
try {
Return to Latch.await (timeout, unit);
catch (Interruptedexception e) {
throw new RuntimeException ("Interrupted waiting for queues", e);
}
}
Class Updatetask implements Runnable {
public void Run () {
while (running) {
try {
Syncindices ();
catch (Throwable e) {
if (Shuttingdown) {
Logger.warn ("Exception occurred during shutdown", e);
} else {
Logger.error ("Problem Handling SOLR Indexing updating", e);
}
}
}
Logger.info ("Shut down Solrindexer");
}
}
void Syncindices () throws Interruptedexception {
Operation op = Inputqueue.poll (1000L, timeunit.milliseconds);
if (op = null) {
Return
}
if (op instanceof stopoperation) {
((stopoperation) op). Stop ();
Return
}
Wait 1 second
try {
Thread.Sleep (1000);
catch (Interruptedexception e) {
}
list<operation> Ops = new arraylist<operation> (inputqueue.size () + 1);
Ops.add (OP);
Inputqueue.drainto (OPS);
map<string, list<indexable>> deletemap = new hashmap<string, list<indexable>> (4);
map<string, list<indexable>> updatemap = new hashmap<string, list<indexable>> (4);
for (Operation o:ops) {
if (o instanceof stopoperation) {
((stopoperation) O). Stop ();
} else {
indexable indexable = o.indexable;
if (O.type = = Operationtype.delete) {
list<indexable> docs = deletemap.get (Indexable.gettype ());
if (docs = = null) {
Docs = new linkedlist<indexable> ();
Deletemap.put (Indexable.gettype (), docs);
}
Docs.add (indexable);
} else {
list<indexable> docs = updatemap.get (Indexable.gettype ());
if (docs = = null) {
Docs = new linkedlist<indexable> ();
Updatemap.put (Indexable.gettype (), docs);
}
Docs.add (indexable);
}
}
}
For (iterator<map.entry<string, list<indexable>>> i = Deletemap.entryset (). Iterator (); I.hasNext () ;) {
map.entry<string, list<indexable>> Entry = I.next ();
Delindices (Entry.getkey (), Entry.getvalue ());
}
For (iterator<map.entry<string, list<indexable>>> i = Updatemap.entryset (). Iterator (); I.hasNext () ;) {
map.entry<string, list<indexable>> Entry = I.next ();
Updateindices (Entry.getkey (), Entry.getvalue ());
}
}
Enum Operationtype {DELETE, UPDATE, SHUTDOWN}
Static Class Operation {
Operationtype type;
Indexable indexable;
Operation () {}
Operation (indexable indexable, Operationtype type) {
this.indexable = indexable;
This.type = type;
}
}
Static Class Stopoperation extends Operation {
Countdownlatch latch;
Stopoperation (Countdownlatch latch) {
This.latch = latch;
This.type = Operationtype.shutdown;
}
public void Stop () {
Latch.countdown ();
}
}
~ Accessors ===============
}