/**
* This software is licensed to you under the Apache License, Version 2.0 (the
* "Apache License").
*
* LinkedIn's contributions are made under the Apache License. If you contribute
* to the Software, the contributions will be deemed to have been made under the
* Apache License, unless you expressly indicate otherwise. Please do not make any
* contributions that would be inconsistent with the Apache License.
*
* You may obtain a copy of the Apache License at http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, this software
* distributed under the Apache License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the Apache
* License for the specific language governing permissions and limitations for the
* software governed under the Apache License.
*
* © 2012 LinkedIn Corp. All Rights Reserved.
*/
package com.senseidb.search.node.inmemory;
import java.io.File;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.management.MBeanServer;
import com.browseengine.bobo.facets.filter.AdaptiveFacetFilter;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.Version;
import org.json.JSONException;
import org.json.JSONObject;
import proj.zoie.api.ZoieIndexReader;
import proj.zoie.api.ZoieMultiReader;
import proj.zoie.api.ZoieSegmentReader;
import proj.zoie.api.indexing.AbstractZoieIndexable;
import proj.zoie.api.indexing.ZoieIndexable;
import proj.zoie.impl.indexing.ZoieConfig;
import com.browseengine.bobo.api.BoboIndexReader;
import com.browseengine.bobo.facets.FacetHandler;
import com.browseengine.bobo.facets.RuntimeFacetHandlerFactory;
import com.senseidb.conf.SenseiFacetHandlerBuilder;
import com.senseidb.conf.SenseiSchema;
import com.senseidb.conf.SenseiServerBuilder;
import com.senseidb.indexing.DefaultJsonSchemaInterpreter;
import com.senseidb.indexing.ShardingStrategy;
import com.senseidb.indexing.activity.ActivityPersistenceFactory;
import com.senseidb.jmx.JmxUtil;
import com.senseidb.jmx.MockJMXServer;
import com.senseidb.plugin.SenseiPluginRegistry;
import com.senseidb.search.node.SenseiIndexReaderDecorator;
import com.senseidb.search.plugin.PluggableSearchEngineManager;
import com.senseidb.search.req.SenseiRequest;
import com.senseidb.search.req.SenseiResult;
import com.senseidb.search.req.SenseiSystemInfo;
import com.senseidb.svc.impl.CoreSenseiServiceImpl;
public class InMemorySenseiService {
private DefaultJsonSchemaInterpreter defaultJsonSchemaInterpreter;
private List<FacetHandler<?>> facets;
private List<RuntimeFacetHandlerFactory<?, ?>> runtimeFacets;
private CoreSenseiServiceImpl coreSenseiServiceImpl;
private PluggableSearchEngineManager pluggableSearchEngineManager;
private MockSenseiCore mockSenseiCore;
private SenseiSystemInfo senseiSystemInfo;
private SenseiIndexReaderDecorator senseiIndexReaderDecorator;
public InMemorySenseiService(SenseiSchema schema, SenseiPluginRegistry pluginRegistry) {
MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
schema.setCompressSrcData(false);
try {
platformMBeanServer = JmxUtil.registerNewJmxServer(new MockJMXServer());
defaultJsonSchemaInterpreter = new DefaultJsonSchemaInterpreter(schema);
facets = new ArrayList<FacetHandler<?>>();
runtimeFacets = new ArrayList<RuntimeFacetHandlerFactory<?, ?>>();
ShardingStrategy strategy = new ShardingStrategy() {
public int caculateShard(int maxShardId, JSONObject dataObj) throws JSONException {
return 0;
}
};
ActivityPersistenceFactory.setOverrideForCurrentThread(ActivityPersistenceFactory.getInMemoryInstance());
pluggableSearchEngineManager = new PluggableSearchEngineManager();
pluggableSearchEngineManager.init("", 0, schema, ZoieConfig.DEFAULT_VERSION_COMPARATOR, pluginRegistry, strategy);
senseiSystemInfo = SenseiFacetHandlerBuilder.buildFacets(schema.getSchemaObj(), pluginRegistry, facets, runtimeFacets,
pluggableSearchEngineManager, AdaptiveFacetFilter.DEFAULT_INVERTED_INDEX_PENALTY);
int[] partitions = new int[] { 0 };
senseiIndexReaderDecorator = new SenseiIndexReaderDecorator(facets, runtimeFacets);
mockSenseiCore = new MockSenseiCore(partitions, senseiIndexReaderDecorator);
pluggableSearchEngineManager.start(mockSenseiCore);
coreSenseiServiceImpl = new CoreSenseiServiceImpl(mockSenseiCore);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
JmxUtil.registerNewJmxServer(platformMBeanServer);
ActivityPersistenceFactory.setOverrideForCurrentThread(null);
}
}
private void addDocuments(Directory directory, IndexWriter writer, List<JSONObject> documents) {
try {
writer.deleteAll();
for (JSONObject doc : documents) {
if (doc == null)
continue;
writer.addDocument(buildDoc(doc));
pluggableSearchEngineManager.update(doc, "");
}
writer.commit();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@SuppressWarnings("unchecked")
public SenseiResult doQuery(SenseiRequest senseiRequest, List<JSONObject> documents) {
Directory directory = null;
IndexWriter writer = null;
try {
directory = new RAMDirectory();
writer = new IndexWriter(directory, new IndexWriterConfig(Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35)));
addDocuments(directory, writer, documents);
ZoieIndexReader<BoboIndexReader> zoieMultiReader = new ZoieMultiReader<BoboIndexReader>(IndexReader.open(directory),
new SenseiIndexReaderDecorator(facets, runtimeFacets));
MockIndexReaderFactory mockIndexReaderFactory = new MockIndexReaderFactory<ZoieIndexReader<BoboIndexReader>>(
Arrays.asList(zoieMultiReader));
mockSenseiCore.setIndexReaderFactory(mockIndexReaderFactory);
SenseiResult result = coreSenseiServiceImpl.execute(senseiRequest);
mockSenseiCore.setIndexReaderFactory(null);
return result;
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
if (writer != null) {
writer.close();
}
if (directory != null) {
directory.close();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
public Document buildDoc(JSONObject json) {
ZoieIndexable indexable = defaultJsonSchemaInterpreter.convertAndInterpret(json);
Document ret = indexable.buildIndexingReqs()[0].getDocument();
ret.add(new Field(AbstractZoieIndexable.DOCUMENT_STORE_FIELD, indexable.getStoreValue()));
ZoieSegmentReader.fillDocumentID(ret, indexable.getUID());
return ret;
}
public static InMemorySenseiService valueOf(File confDir) {
try {
JSONObject schema = SenseiServerBuilder.loadSchema(confDir);
File senseiConfFile = new File(confDir, SenseiServerBuilder.SENSEI_PROPERTIES);
if (!senseiConfFile.exists()) {
throw new ConfigurationException("configuration file: " + senseiConfFile.getAbsolutePath() + " does not exist.");
}
Configuration senseiConf = new PropertiesConfiguration();
((PropertiesConfiguration) senseiConf).setDelimiterParsingDisabled(true);
((PropertiesConfiguration) senseiConf).load(senseiConfFile);
return new InMemorySenseiService(SenseiSchema.build(schema), SenseiPluginRegistry.build(senseiConf));
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
public SenseiSystemInfo getSenseiSystemInfo() {
return senseiSystemInfo;
}
public void setSenseiSystemInfo(SenseiSystemInfo senseiSystemInfo) {
this.senseiSystemInfo = senseiSystemInfo;
}
}