diff --git a/bigdata-core/bigdata-rdf/src/java/com/bigdata/service/fts/FTS.java b/bigdata-core/bigdata-rdf/src/java/com/bigdata/service/fts/FTS.java index 4e5c958672..c05b9561a5 100644 --- a/bigdata-core/bigdata-rdf/src/java/com/bigdata/service/fts/FTS.java +++ b/bigdata-core/bigdata-rdf/src/java/com/bigdata/service/fts/FTS.java @@ -465,4 +465,11 @@ public static enum SearchResultType { */ final URI SCORE_FIELD = new URIImpl(NAMESPACE + "scoreField"); + /** + * Configuration property starting with FTS_CUSTOM_TYPE can be used to specify + * the class that will be handling this type. For example: + * com.bigdata.service.fts.FTS.enpointType.Elastic=com.example.ElasticSearchImpl + * The class should be instance of {@link IFulltextSearch}. + */ + final String FTS_CUSTOM_TYPE = FTS.class.getName() + ".endpointType."; } diff --git a/bigdata-core/bigdata-rdf/src/java/com/bigdata/service/fts/FulltextSearchServiceFactory.java b/bigdata-core/bigdata-rdf/src/java/com/bigdata/service/fts/FulltextSearchServiceFactory.java index ed46daf708..2e8f86e7de 100644 --- a/bigdata-core/bigdata-rdf/src/java/com/bigdata/service/fts/FulltextSearchServiceFactory.java +++ b/bigdata-core/bigdata-rdf/src/java/com/bigdata/service/fts/FulltextSearchServiceFactory.java @@ -120,12 +120,8 @@ public MockIVReturningServiceCall create(final ServiceCallCreateParams params) { throw new IllegalArgumentException(); final AbstractTripleStore store = params.getTripleStore(); - - final Properties props = - store.getIndexManager()!=null && - store.getIndexManager() instanceof AbstractJournal ? - ((AbstractJournal)store.getIndexManager()).getProperties() : null; - + + final Properties props = getStoreProps(params); final FulltextSearchDefaults deflts = new FulltextSearchDefaults(props); final ServiceNode serviceNode = params.getServiceNode(); @@ -164,6 +160,14 @@ public MockIVReturningServiceCall create(final ServiceCallCreateParams params) { } + public static Properties getStoreProps(final ServiceCallCreateParams params) { + final AbstractTripleStore store = params.getTripleStore(); + + return store.getIndexManager()!=null && + store.getIndexManager() instanceof AbstractJournal ? + ((AbstractJournal)store.getIndexManager()).getProperties() : null; + } + /** * Validate the search request. This looks for external search magic * predicates and returns them all. It is an error if anything else is found @@ -774,7 +778,7 @@ private boolean nextDelegate() { final IBindingSet bs = bindingSet[nextBindingSetItr++]; final String query = resolveQuery(bs); final String endpoint = resolveEndpoint(bs); - final EndpointType endpointType = resolveEndpointType(bs); + final String endpointType = resolveEndpointType(bs); final String params = resolveParams(bs); final SearchResultType searchResultType = resolveSearchResultType(bs); final Integer searchTimeout = resolveSearchTimeout(bs); @@ -787,14 +791,7 @@ private boolean nextDelegate() { * Though we currently, we only support Solr, here we might easily hook * in other implementations based on the magic predicate */ - final IFulltextSearch ftSearch; - switch (endpointType) { - - case SOLR: - default: - ftSearch = new SolrFulltextSearchImpl(); - break; - } + final IFulltextSearch ftSearch = getSearchClass(endpointType); FulltextSearchQuery sq = new FulltextSearchQuery( query, params, endpoint, searchTimeout, searchField, @@ -805,6 +802,44 @@ private boolean nextDelegate() { return true; } + private IFulltextSearch getDefaultSearchImpl() { + return new SolrFulltextSearchImpl(); + } + + /** + * Resolve search class to implementation. + * If no suitable one is found, return SolrFulltextSearchImpl + * @param className + * @return + */ + private IFulltextSearch getSearchClass(String className) { + final Class endpointClass; + + if(className == null) { + return getDefaultSearchImpl(); + } + try { + endpointClass = Class.forName(className); + if (!(endpointClass.isInstance(IFulltextSearch.class))) { + if (log.isDebugEnabled()) { + log.warn("Endpoint class: " + endpointType + + " does not implement IFulltextSearch ->" + + " will be ignored, using default."); + } + return getDefaultSearchImpl(); + } else { + return (IFulltextSearch)endpointClass.newInstance(); + } + } catch (Exception e) { + if (log.isDebugEnabled()) { + log.warn("Illegal endpoint class: " + endpointType + + " -> will be ignored, using default."); + } + } + // Default search implementation + return getDefaultSearchImpl(); + } + private void init() { nextDelegate(); @@ -866,7 +901,6 @@ private Integer resolveSearchTimeout(IBindingSet bs) { } if (searchTimeoutStr != null && !searchTimeoutStr.isEmpty()) { - try { return Integer.valueOf(searchTimeoutStr); @@ -903,8 +937,9 @@ private String resolveParams(IBindingSet bs) { /** * Resolves the endpoint type, which is either a constant or a variable to * be looked up in the binding set. + * @return Class name for the endpoint type or null if none found */ - private EndpointType resolveEndpointType(IBindingSet bs) { + private String resolveEndpointType(IBindingSet bs) { String endpointTypeStr = resolveAsString(endpointType, bs); @@ -914,11 +949,16 @@ private EndpointType resolveEndpointType(IBindingSet bs) { } if (endpointTypeStr != null && !endpointTypeStr.isEmpty()) { - - try { - - return EndpointType.valueOf(endpointTypeStr); - + final String endpointName = FTS.FTS_CUSTOM_TYPE + endpointTypeStr; + final Properties props = getStoreProps(serviceCallParams); + try { + if (props.contains(endpointName)) { + return props.getProperty(endpointName); + } + switch(EndpointType.valueOf(endpointTypeStr)) { + case SOLR: + return SolrFulltextSearchImpl.class.getName(); + } } catch (Exception e) { // illegal, ignore and proceed @@ -930,8 +970,7 @@ private EndpointType resolveEndpointType(IBindingSet bs) { } } - return FTS.Options.DEFAULT_ENDPOINT_TYPE; // fallback - + return null; // fallback to default } /**