diff --git a/pom.xml b/pom.xml index fefa249..5f4ed38 100644 --- a/pom.xml +++ b/pom.xml @@ -4,14 +4,14 @@ lutece-global-pom fr.paris.lutece.tools - 3.0 + 4.0.3 4.0.0 fr.paris.lutece.plugins plugin-solr lutece-plugin - 3.0.1-SNAPSHOT + 3.0.4-SNAPSHOT Lutece solr search plugin @@ -35,13 +35,19 @@ fr.paris.lutece lutece-core - [4.9.9,) + [6.1.0,) lutece-core org.apache.solr solr-solrj - 5.1.0 + 6.5.1 + + + fr.paris.lutece.plugins + plugin-leaflet + 1.0.0-SNAPSHOT + lutece-plugin @@ -55,6 +61,7 @@ scm:git:https://github.com/lutece-platform/lutece-search-plugin-solr.git scm:git:https://github.com/lutece-platform/lutece-search-plugin-solr.git https://github.com/lutece-platform/lutece-search-plugin-solr.git - + HEAD + diff --git a/src/java/fr/paris/lutece/plugins/search/resources/search_messages.properties b/src/java/fr/paris/lutece/plugins/search/resources/search_messages.properties index dcb1db8..fc49346 100644 --- a/src/java/fr/paris/lutece/plugins/search/resources/search_messages.properties +++ b/src/java/fr/paris/lutece/plugins/search/resources/search_messages.properties @@ -31,12 +31,10 @@ solr.adminFeature.fields.form.type=Type solr.adminFeature.fields.form.facet=Facet solr.adminFeature.fields.form.sort=Sort solr.adminFeature.fields.form.description=Description -solr.adminFeature.fields.form.weight=Weight -solr.adminFeature.fields.form.weight.low=Low -solr.adminFeature.fields.form.weight.normal=Normal -solr.adminFeature.fields.form.weight.high=High solr.adminFeature.fields.form.actions=Actions solr.adminFeature.buttonDoDel=Del solr index +solr.adminFeature.operationInProgress=Operation in progress +solr.adminFeature.operationDone=Operation done #Display solr result solr.display.result.spellchecker=Try with this : diff --git a/src/java/fr/paris/lutece/plugins/search/resources/search_messages_fr.properties b/src/java/fr/paris/lutece/plugins/search/resources/search_messages_fr.properties index 7f6fdd8..52179d6 100644 --- a/src/java/fr/paris/lutece/plugins/search/resources/search_messages_fr.properties +++ b/src/java/fr/paris/lutece/plugins/search/resources/search_messages_fr.properties @@ -7,36 +7,34 @@ solr.adminFeature.description=Indexe le contenu dans Solr. #Admin configuration solr search solr.adminFeature.configuration.title=Configuration de Solr -solr.adminFeature.configuration.description=Configuration des propriétés de recherche du moteur Solr +solr.adminFeature.configuration.description=Configuration des propri\u00e9t\u00e9s de recherche du moteur Solr solr.adminFeature.configuration.facet.title=Configuration des facettes -solr.adminFeature.configuration.facet.description=Selectionner les facetes utilisées pour la recherche. +solr.adminFeature.configuration.facet.description=Selectionner les facetes utilis\u00e9es pour la recherche. solr.adminFeature.configuration.sort.title=Configuration des champs de tri -solr.adminFeature.configuration.sort.description=Selectionner les champs utilisés pour le tri lors de la recherche. +solr.adminFeature.configuration.sort.description=Selectionner les champs utilis\u00e9s pour le tri lors de la recherche. solr.adminFeature.configuration.intersection.title=Intersection de Facettes solr.adminFeature.configuration.intersection.description=Selectionner deux facettes pour obtenir leurs intersections solr.adminFeature.configuration.intersection.field1=Champ 1 solr.adminFeature.configuration.intersection.field2=Champ 2 -solr.adminFeature.configuration.valid=Modification sauvegardé +solr.adminFeature.configuration.valid=Modification sauvegard\u00e9 #Admin Solr Fields Management solr.adminFeature.fields.title=Gestion des champs Solr -solr.adminFeature.fields.description=Permet l'ajout, l'update et la suppression de champs solr utilsé dans la partie configuration. +solr.adminFeature.fields.description=Permet l'ajout, l'update et la suppression de champs solr utils\u00e9 dans la partie configuration. solr.adminFeature.fields.display.title=Champs Solr disponible solr.adminFeature.fields.display.description=Liste des champs Solr disponible pour la configuration des facettes, tri, ect ... -solr.adminFeature.fields.form.create.title=Création d'un champs -solr.adminFeature.fields.form.update.title=Mise à jour d'un champs +solr.adminFeature.fields.form.create.title=Cr\u00e9ation d'un champs +solr.adminFeature.fields.form.update.title=Mise \u00e0 jour d'un champs solr.adminFeature.fields.form.name=Nom solr.adminFeature.fields.form.label=Label solr.adminFeature.fields.form.type=Type solr.adminFeature.fields.form.facet=Facette solr.adminFeature.fields.form.sort=Tri solr.adminFeature.fields.form.description=Description -solr.adminFeature.fields.form.weight.low=Basse -solr.adminFeature.fields.form.weight.normal=Normal -solr.adminFeature.fields.form.weight.high=Haute -solr.adminFeature.fields.form.weight=Pondération solr.adminFeature.fields.form.actions=Actions solr.adminFeature.buttonDoDel=Effacer l'index +solr.adminFeature.operationInProgress=Op\u00e9ration en cours +solr.adminFeature.operationDone=Op\u00e9ration termin\u00e9e #Display solr result solr.display.result.spellchecker=Essayez avec ceci : diff --git a/src/java/fr/paris/lutece/plugins/search/solr/business/SolrFacetedResult.java b/src/java/fr/paris/lutece/plugins/search/solr/business/SolrFacetedResult.java index a7ab366..3acbb81 100644 --- a/src/java/fr/paris/lutece/plugins/search/solr/business/SolrFacetedResult.java +++ b/src/java/fr/paris/lutece/plugins/search/solr/business/SolrFacetedResult.java @@ -34,7 +34,6 @@ package fr.paris.lutece.plugins.search.solr.business; import org.apache.solr.client.solrj.response.FacetField; -import org.apache.solr.client.solrj.response.SpellCheckResponse; import java.util.ArrayList; import java.util.List; @@ -61,9 +60,6 @@ public class SolrFacetedResult /**Commentaire. **/ private Map> facetIntersection; - /**spellcheck. **/ - private SpellCheckResponse solrSpellCheckResponse; - private int _nCount; /** @@ -143,12 +139,4 @@ public final void setFacetIntersection( Map> facet { this.facetIntersection = facetIntersection; } - - public SpellCheckResponse getSolrSpellCheckResponse() { - return this.solrSpellCheckResponse; - } - - public void setSolrSpellCheckResponse(SpellCheckResponse solrSpellCheckResponse) { - this.solrSpellCheckResponse = solrSpellCheckResponse; - } } diff --git a/src/java/fr/paris/lutece/plugins/search/solr/business/SolrSearchAppConf.java b/src/java/fr/paris/lutece/plugins/search/solr/business/SolrSearchAppConf.java new file mode 100644 index 0000000..c2d23c2 --- /dev/null +++ b/src/java/fr/paris/lutece/plugins/search/solr/business/SolrSearchAppConf.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2002-2015, Mairie de Paris + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright notice + * and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice + * and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * License 1.0 + */ +package fr.paris.lutece.plugins.search.solr.business; + +import java.util.ArrayList; +import java.util.List; + +import fr.paris.lutece.plugins.search.solr.service.SolrSearchAppConfService; +import fr.paris.lutece.plugins.search.solr.util.SolrConstants; + + +/** + * + * SolrSearchAppConf + * + */ +public class SolrSearchAppConf +{ + private String _strCode = SolrSearchAppConfService.EMPTY_CODE; + private String _strFilterQuery = SolrConstants.CONSTANT_DEFAULT_FILTER_QUERY; + private String _strTemplate = SolrConstants.CONSTANT_DEFAULT_TEMPLATE; + private boolean _bExtraMappingQuery = SolrConstants.CONSTANT_DEFAULT_EXTRA_MAPPING_QUERY; + private List _listAddonBeanNames = new ArrayList( ); + + /** + * Returns the code + * @return the code + */ + public String getCode( ) + { + return _strCode; + } + + /** + * Sets the code + * @param code the code + */ + public void setCode( String code ) + { + _strCode = code; + } + + /** + * Returns the template + * @return the template + */ + public String getTemplate( ) + { + return _strTemplate; + } + + /** + * Sets the template + * @param template the template + */ + public void setTemplate( String template ) + { + _strTemplate = template; + } + + /** + * Returns the filter query + * @return the filter query + */ + public String getFilterQuery( ) + { + return _strFilterQuery; + } + + /** + * Sets the filter query + * @param filter query the code + */ + public void setFilterQuery( String strFilterQuery ) + { + _strFilterQuery = strFilterQuery; + } + + /** + * Returns the boolean indicating if we need an extra query for mapping + * @return the boolean indicating if we need an extra query for mapping + */ + public boolean getExtraMappingQuery( ) + { + return _bExtraMappingQuery; + } + + /** + * Sets the boolean indicating if we need an extra query for mapping + * @param bExtraMappingQuery the boolean indicating if we need an extra query for mapping + */ + public void setExtraMappingQuery( boolean bExtraMappingQuery ) + { + _bExtraMappingQuery = bExtraMappingQuery; + } + + /** + * @return the AddonBeanNames + */ + public List getAddonBeanNames() { + return _listAddonBeanNames; + } + + /** + * @param listAddonBeanNames the AddonBeanNames to set + */ + public void setAddonBeanNames(List listAddonBeanNames) { + this._listAddonBeanNames = listAddonBeanNames; + } +} diff --git a/src/java/fr/paris/lutece/plugins/search/solr/business/SolrSearchEngine.java b/src/java/fr/paris/lutece/plugins/search/solr/business/SolrSearchEngine.java index 87026e4..586359f 100644 --- a/src/java/fr/paris/lutece/plugins/search/solr/business/SolrSearchEngine.java +++ b/src/java/fr/paris/lutece/plugins/search/solr/business/SolrSearchEngine.java @@ -36,6 +36,7 @@ import fr.paris.lutece.plugins.search.solr.business.facetIntersection.FacetIntersection; import fr.paris.lutece.plugins.search.solr.business.field.Field; import fr.paris.lutece.plugins.search.solr.business.field.SolrFieldManager; +import fr.paris.lutece.plugins.search.solr.indexer.SolrIndexerService; import fr.paris.lutece.plugins.search.solr.indexer.SolrItem; import fr.paris.lutece.plugins.search.solr.util.SolrConstants; import fr.paris.lutece.plugins.search.solr.util.SolrUtil; @@ -48,9 +49,9 @@ import fr.paris.lutece.portal.service.util.AppLogService; import fr.paris.lutece.portal.service.util.AppPropertiesService; +import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.SolrQuery.ORDER; -import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.response.FacetField; import org.apache.solr.client.solrj.response.QueryResponse; @@ -75,15 +76,13 @@ */ public class SolrSearchEngine implements SearchEngine { - private static final String PROPERTY_SOLR_AUTOCOMPLETE_HANDLER = "solr.autocomplete.handler"; - private static final String PROPERTY_SOLR_SPELLCHECK_HANDLER = "solr.spellcheck.handler"; - private static final String PROPERTY_SOLR_HIGHLIGHT_PRE = "solr.highlight.pre"; + private static final String PROPERTY_SOLR_HIGHLIGHT_PRE = "solr.highlight.pre"; private static final String PROPERTY_SOLR_HIGHLIGHT_POST = "solr.highlight.post"; private static final String PROPERTY_SOLR_HIGHLIGHT_SNIPPETS = "solr.highlight.snippets"; private static final String PROPERTY_SOLR_HIGHLIGHT_FRAGSIZE = "solr.highlight.fragsize"; private static final String PROPERTY_SOLR_FACET_DATE_START = "solr.facet.date.start"; - private static final String SOLR_AUTOCOMPLETE_HANDLER = AppPropertiesService.getProperty(PROPERTY_SOLR_AUTOCOMPLETE_HANDLER); - private static final String SOLR_SPELLCHECK_HANDLER = AppPropertiesService.getProperty(PROPERTY_SOLR_SPELLCHECK_HANDLER); + private static final String PROPERTY_SOLR_FACET_MIN_COUNT = "solr.facet.minCount"; + private static final String SOLR_HIGHLIGHT_PRE = AppPropertiesService.getProperty( PROPERTY_SOLR_HIGHLIGHT_PRE ); private static final String SOLR_HIGHLIGHT_POST = AppPropertiesService.getProperty( PROPERTY_SOLR_HIGHLIGHT_POST ); private static final int SOLR_HIGHLIGHT_SNIPPETS = AppPropertiesService.getPropertyInt( PROPERTY_SOLR_HIGHLIGHT_SNIPPETS, @@ -91,14 +90,19 @@ public class SolrSearchEngine implements SearchEngine private static final int SOLR_HIGHLIGHT_FRAGSIZE = AppPropertiesService.getPropertyInt( PROPERTY_SOLR_HIGHLIGHT_FRAGSIZE, 100 ); private static final String SOLR_FACET_DATE_START = AppPropertiesService.getProperty( PROPERTY_SOLR_FACET_DATE_START ); + private static final int SOLR_FACET_MIN_COUNT = AppPropertiesService.getPropertyInt(PROPERTY_SOLR_FACET_MIN_COUNT, 1); + public static final String SOLR_FACET_DATE_GAP = AppPropertiesService.getProperty( "solr.facet.date.gap", "+1YEAR" ); public static final String SOLR_FACET_DATE_END = AppPropertiesService .getProperty( "solr.facet.date.end", "NOW" ); public static final int SOLR_FACET_LIMIT = AppPropertiesService.getPropertyInt( "solr.facet.limit", 100 ); + + private static SolrSearchEngine _instance; private static final String COLON_QUOTE = ":\""; private static final String DATE_COLON = "date:"; - private static final String DEF_TYPE = "dismax"; + private static final String DEFAULT_FIELD = "content"; + private static final String ALL_SEARCH_QUERY = "*:*"; /** * Return search results @@ -118,6 +122,10 @@ public List getSearchResults( String strQuery, HttpServletRequest if ( ( strQuery != null ) && ( strQuery.length( ) > 0 ) ) { + if ( !strQuery.equals( ALL_SEARCH_QUERY ) ) + { + strQuery = buildQueryWithDefaultField( strQuery ); + } query.setQuery( strQuery ); } @@ -159,9 +167,11 @@ public List getSearchResults( String strQuery, HttpServletRequest catch ( SolrServerException e ) { AppLogService.error( e.getMessage( ), e ); - } catch (IOException e) { - AppLogService.error( e.getMessage( ), e ); - } + } + catch ( IOException e ) + { + AppLogService.error( e.getMessage( ), e ); + } } return results; @@ -177,7 +187,7 @@ public List getSearchResults( String strQuery, HttpServletRequest * @return the result with facets */ public SolrFacetedResult getFacetedSearchResults( String strQuery, String[] facetQueries, String sortName, - String sortOrder, int nLimit, int nCurrentPageIndex, int nItemsPerPage, Boolean bSpellCheck ) + String sortOrder, int nLimit, int nCurrentPageIndex, int nItemsPerPage ) { SolrFacetedResult facetedResult = new SolrFacetedResult( ); @@ -186,6 +196,11 @@ public SolrFacetedResult getFacetedSearchResults( String strQuery, String[] face if ( solrServer != null ) { + if ( !strQuery.equals( ALL_SEARCH_QUERY ) ) + { + strQuery = buildQueryWithDefaultField( strQuery ); + } + SolrQuery query = new SolrQuery( strQuery ); query.setHighlight( true ); query.setHighlightSimplePre( SOLR_HIGHLIGHT_PRE ); @@ -194,7 +209,7 @@ public SolrFacetedResult getFacetedSearchResults( String strQuery, String[] face query.setHighlightFragsize( SOLR_HIGHLIGHT_FRAGSIZE ); query.setFacet( true ); query.setFacetLimit( SOLR_FACET_LIMIT ); - query.setFacetMinCount( 1 ); + query.setFacetMinCount( SOLR_FACET_MIN_COUNT ); for ( Field field : SolrFieldManager.getFacetList( ).values( ) ) { @@ -226,8 +241,7 @@ public SolrFacetedResult getFacetedSearchResults( String strQuery, String[] face //(String []) al.toArray (new String [0]); query.setParam( "facet.tree", (String[]) treeParam.toArray( new String[0] ) ); - query.setParam( "spellcheck", bSpellCheck); - + //sort order if ( ( sortName != null ) && !"".equals( sortName ) ) { @@ -235,9 +249,13 @@ public SolrFacetedResult getFacetedSearchResults( String strQuery, String[] face { query.setSort( sortName, ORDER.asc ); } + else if(sortOrder.equals("random")) + { + query.setParam( "sort", sortName+"_random asc" ); + } else { - query.setSort( sortName, ORDER.desc ); + query.setSort( sortName, ORDER.desc ); } } else @@ -263,10 +281,14 @@ public SolrFacetedResult getFacetedSearchResults( String strQuery, String[] face } else { - String strFacetQueryWithColon; - strFacetQueryWithColon = strFacetQuery.replaceFirst( SolrConstants.CONSTANT_COLON, COLON_QUOTE ); - strFacetQueryWithColon += SolrConstants.CONSTANT_QUOTE; - query.addFilterQuery( strFacetQueryWithColon ); + if ( strFacetQuery.indexOf( SolrConstants.CONSTANT_COLON ) >= 0 ) { + String strFacetQueryWithColon; + strFacetQueryWithColon = strFacetQuery.replaceFirst( SolrConstants.CONSTANT_COLON, COLON_QUOTE ); + strFacetQueryWithColon += SolrConstants.CONSTANT_QUOTE; + query.addFilterQuery( strFacetQueryWithColon ); + } else { + query.addFilterQuery( strFacetQuery ); + } } } } @@ -276,6 +298,7 @@ public SolrFacetedResult getFacetedSearchResults( String strQuery, String[] face // count query query.setRows( 0 ); + QueryResponse response = solrServer.query( query ); int nResults = (int) response.getResults().getNumFound( ); @@ -283,11 +306,6 @@ public SolrFacetedResult getFacetedSearchResults( String strQuery, String[] face query.setStart( ( nCurrentPageIndex - 1 ) * nItemsPerPage ); query.setRows( nItemsPerPage > nLimit ? nLimit : nItemsPerPage ); - - query.setParam("defType", DEF_TYPE); - String strWeightValue = generateQueryWeightValue(); - query.setParam("qf", strWeightValue); - response = solrServer.query( query ); //HighLight @@ -303,9 +321,6 @@ public SolrFacetedResult getFacetedSearchResults( String strQuery, String[] face List itemList = response.getBeans( SolrItem.class ); results = SolrUtil.transformSolrItemsToSolrSearchResults( itemList, highlights ); - //set the spellcheckresult - facetedResult.setSolrSpellCheckResponse(response.getSpellCheckResponse()); - //Date facet if ( ( response.getFacetDates( ) != null ) && !response.getFacetDates( ).isEmpty( ) ) { @@ -358,9 +373,11 @@ public SolrFacetedResult getFacetedSearchResults( String strQuery, String[] face catch ( SolrServerException e ) { AppLogService.error( e.getMessage( ), e ); - } catch (IOException e) { - AppLogService.error( e.getMessage( ), e ); - } + } + catch ( IOException e ) + { + AppLogService.error( e.getMessage( ), e ); + } } else { @@ -372,17 +389,73 @@ public SolrFacetedResult getFacetedSearchResults( String strQuery, String[] face return facetedResult; } - private String generateQueryWeightValue() { - List fieldList = SolrFieldManager.getFieldList(); - String strQueryWeight = ""; - for (Field field : fieldList) - { - strQueryWeight += field.getSolrName() + "^" + field.getWeight() + " " ; - } - return strQueryWeight; - } - - /** + /** + * Return the result geojseon and uid + * @param strQuery the query + * @param facetQueries The selected facets + * @param nLimit Maximal number of results. + * @return the results geojson and uid + */ + public List getGeolocSearchResults( String strQuery, String[] facetQueries, int nLimit ) + { + SolrClient solrServer = SolrServerService.getInstance( ).getSolrServer( ); + if ( solrServer != null ) { + String strFields = "*" + SolrItem.DYNAMIC_GEOJSON_FIELD_SUFFIX + "," + SearchItem.FIELD_UID ; + if ( !strQuery.equals( ALL_SEARCH_QUERY ) ) + { + strQuery = buildQueryWithDefaultField( strQuery ); + } + SolrQuery query = new SolrQuery( strQuery ); + query.setParam ( "fl", strFields ); + + //Treat HttpRequest + //FacetQuery + if ( facetQueries != null ) + { + for ( String strFacetQuery : facetQueries ) + { + if ( strFacetQuery.contains( DATE_COLON ) ) + { + query.addFilterQuery( strFacetQuery ); + } + else + { + if ( strFacetQuery.indexOf( SolrConstants.CONSTANT_COLON ) >= 0 ) { + String strFacetQueryWithColon; + strFacetQueryWithColon = strFacetQuery.replaceFirst( SolrConstants.CONSTANT_COLON, COLON_QUOTE ); + strFacetQueryWithColon += SolrConstants.CONSTANT_QUOTE; + query.addFilterQuery( strFacetQueryWithColon ); + } else { + query.addFilterQuery( strFacetQuery ); + } + } + } + } + + query.setStart( 0 ); + query.setRows( nLimit ); + QueryResponse response; + try { + response = solrServer.query(query); + } catch (SolrServerException e) { + AppLogService.error( "Solr getGeolocSearchResults error: " + e.getMessage( ), e ); + return new ArrayList(); + } + catch ( IOException e ) + { + AppLogService.error( e.getMessage( ), e ); + return new ArrayList(); + } + + //resultList + List itemList = response.getBeans( SolrItem.class ); + return SolrUtil.transformSolrItemsToSolrSearchResults( itemList, null ); + } else { + return new ArrayList(); + } + } + + /** * Return the suggestion terms * @param term the terms of search * @return The spell checker response @@ -398,9 +471,6 @@ public SpellCheckResponse getSpellChecker( String term ) //Activate spellChecker query.setParam( "spellcheck", "true" ); //The request handler used - query.setRequestHandler(SOLR_SPELLCHECK_HANDLER ); - //The number of suggest returned - query.setParam( "spellcheck.count", "1" ); // TODO //Returns the frequency of the terms @@ -417,9 +487,11 @@ public SpellCheckResponse getSpellChecker( String term ) catch ( SolrServerException e ) { AppLogService.error( e.getMessage( ), e ); - } catch (IOException e) { - AppLogService.error( e.getMessage( ), e ); - } + } + catch ( IOException e ) + { + AppLogService.error( e.getMessage( ), e ); + } return spellCheck; } @@ -433,7 +505,7 @@ public QueryResponse getJsonpSuggest( String terms, String callback ) query.setParam( "wt", "json" ); query.setParam( "json.wrf", callback ); query.setRows( 10 ); - query.setRequestHandler( "/" + SOLR_AUTOCOMPLETE_HANDLER ); + query.setRequestHandler("/autoComplete" ); //TODO try { @@ -442,15 +514,18 @@ public QueryResponse getJsonpSuggest( String terms, String callback ) catch ( SolrServerException e ) { AppLogService.error( e.getMessage( ), e ); - } catch (IOException e) { - AppLogService.error( e.getMessage( ), e ); - } + } + catch ( IOException e ) + { + AppLogService.error( e.getMessage( ), e ); + } return response; } public String getDocumentHighLighting( String strDocumentId, String terms ) { + String strDocumentIdPrefixed = SolrIndexerService.getWebAppName() + SolrConstants.CONSTANT_UNDERSCORE + strDocumentId; String xmlContent = null; SolrClient solrServer = SolrServerService.getInstance( ).getSolrServer( ); SolrQuery query = new SolrQuery( terms ); @@ -461,7 +536,7 @@ public String getDocumentHighLighting( String strDocumentId, String terms ) query.setParam( "hl.fl", SolrItem.FIELD_XML_CONTENT ); //return only the field xml_content HighLighting query.setFields( SearchItem.FIELD_UID ); //return only the field uid query.setRows( 1 ); - query.addFilterQuery( SearchItem.FIELD_UID + ":" + strDocumentId ); + query.addFilterQuery( SearchItem.FIELD_UID + ":" + strDocumentIdPrefixed ); try { @@ -471,9 +546,9 @@ public String getDocumentHighLighting( String strDocumentId, String terms ) { SolrHighlights highlights = new SolrHighlights( response.getHighlighting( ) ); - if ( highlights.getHighlights( strDocumentId ).getMap( ).size( ) > 0 ) + if ( highlights.getHighlights( strDocumentIdPrefixed ).getMap( ).size( ) > 0 ) { - xmlContent = highlights.getHighlights( strDocumentId ).getMap( ).get( SolrItem.FIELD_XML_CONTENT ) + xmlContent = highlights.getHighlights( strDocumentIdPrefixed ).getMap( ).get( SolrItem.FIELD_XML_CONTENT ) .get( 0 ); } } @@ -481,9 +556,11 @@ public String getDocumentHighLighting( String strDocumentId, String terms ) catch ( SolrServerException e ) { AppLogService.error( e.getMessage( ), e ); - } catch (IOException e) { - AppLogService.error( e.getMessage( ), e ); - } + } + catch ( IOException e ) + { + AppLogService.error( e.getMessage( ), e ); + } return xmlContent; } @@ -513,6 +590,25 @@ private String buildFilter( String strField, String[] values ) return filterString; } + /** + * Builds a query with default field from multiple values. + * @param strMultipleValues the values + * @return the query string + */ + private String buildQueryWithDefaultField( String strMultipleValues ) + { + + String multipleValues[] = strMultipleValues.split("\\s+"); + StringBuffer q = new StringBuffer( ); + + for ( String strValue : multipleValues ) + { + q.append( DEFAULT_FIELD ).append( ":" ).append( strValue ).append( " " ); + } + + return q.toString( ).trim( ); + } + /** * Returns the instance * @return the instance diff --git a/src/java/fr/paris/lutece/plugins/search/solr/business/SolrServerService.java b/src/java/fr/paris/lutece/plugins/search/solr/business/SolrServerService.java index 29ce546..e92a878 100644 --- a/src/java/fr/paris/lutece/plugins/search/solr/business/SolrServerService.java +++ b/src/java/fr/paris/lutece/plugins/search/solr/business/SolrServerService.java @@ -34,9 +34,10 @@ package fr.paris.lutece.plugins.search.solr.business; import fr.paris.lutece.portal.service.util.AppPropertiesService; -import org.apache.solr.client.solrj.SolrClient; +import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.impl.HttpSolrClient; +import org.apache.solr.client.solrj.impl.HttpSolrClient.Builder; /** @@ -99,7 +100,7 @@ public SolrClient getSolrServer( ) */ private SolrClient createSolrServer( String strServerUrl ) { - HttpSolrClient solrServer = new HttpSolrClient( strServerUrl ); + HttpSolrClient solrServer = new Builder( strServerUrl ).build( ); if ( SOLR_SERVER_MAX_CONNECTION != NO_MAX_CONNECTION_SET ) { solrServer.setMaxTotalConnections( SOLR_SERVER_MAX_CONNECTION ); diff --git a/src/java/fr/paris/lutece/plugins/search/solr/business/field/Field.java b/src/java/fr/paris/lutece/plugins/search/solr/business/field/Field.java index c83723e..f0c6f74 100644 --- a/src/java/fr/paris/lutece/plugins/search/solr/business/field/Field.java +++ b/src/java/fr/paris/lutece/plugins/search/solr/business/field/Field.java @@ -49,7 +49,6 @@ public class Field private boolean _IsSort; private boolean _EnableSort; private boolean _DefaultSort; - private double _Weight; public Field( ) { @@ -229,22 +228,4 @@ public void setDefaultSort( boolean DefaultSort ) { _DefaultSort = DefaultSort; } - - /** - * Sets the weight - * @param Weight The Weight - */ - public void setWeight( double dWeight ) { - _Weight = dWeight; - - } - - /** - * Returns the weight - * @return The weight - */ - public double getWeight( ) - { - return _Weight; - } } diff --git a/src/java/fr/paris/lutece/plugins/search/solr/business/field/FieldDAO.java b/src/java/fr/paris/lutece/plugins/search/solr/business/field/FieldDAO.java index 3a4fea1..9ddba90 100644 --- a/src/java/fr/paris/lutece/plugins/search/solr/business/field/FieldDAO.java +++ b/src/java/fr/paris/lutece/plugins/search/solr/business/field/FieldDAO.java @@ -47,11 +47,11 @@ public final class FieldDAO implements IFieldDAO { // Constants private static final String SQL_QUERY_NEW_PK = "SELECT max( id_field ) FROM solr_fields"; - private static final String SQL_QUERY_SELECT = "SELECT id_field, name, label, description, is_facet, enable_facet, is_sort, enable_sort, default_sort, weight FROM solr_fields WHERE id_field = ?"; - private static final String SQL_QUERY_INSERT = "INSERT INTO solr_fields ( id_field, name, label, description, is_facet, enable_facet, is_sort, enable_sort, default_sort, weight ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) "; + private static final String SQL_QUERY_SELECT = "SELECT id_field, name, label, description, is_facet, enable_facet, is_sort, enable_sort, default_sort FROM solr_fields WHERE id_field = ?"; + private static final String SQL_QUERY_INSERT = "INSERT INTO solr_fields ( id_field, name, label, description, is_facet, enable_facet, is_sort, enable_sort, default_sort ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ? ) "; private static final String SQL_QUERY_DELETE = "DELETE FROM solr_fields WHERE id_field = ? "; - private static final String SQL_QUERY_UPDATE = "UPDATE solr_fields SET id_field = ?, name = ?, label = ?, description = ?, is_facet = ?, enable_facet = ?, is_sort = ?, enable_sort = ?, default_sort = ?, weight = ? WHERE id_field = ?"; - private static final String SQL_QUERY_SELECTALL = "SELECT id_field, name, label, description, is_facet, enable_facet, is_sort, enable_sort, default_sort, weight FROM solr_fields"; + private static final String SQL_QUERY_UPDATE = "UPDATE solr_fields SET id_field = ?, name = ?, label = ?, description = ?, is_facet = ?, enable_facet = ?, is_sort = ?, enable_sort = ?, default_sort = ? WHERE id_field = ?"; + private static final String SQL_QUERY_SELECTALL = "SELECT id_field, name, label, description, is_facet, enable_facet, is_sort, enable_sort, default_sort FROM solr_fields"; /** * Generates a new primary key @@ -98,7 +98,6 @@ public void insert( Field field, Plugin plugin ) daoUtil.setBoolean( i++, field.getIsSort( ) ); daoUtil.setBoolean( i++, field.getEnableSort( ) ); daoUtil.setBoolean( i++, field.getDefaultSort( ) ); - daoUtil.setDouble( i++, field.getWeight() ); daoUtil.executeUpdate( ); daoUtil.free( ); @@ -132,7 +131,6 @@ public Field load( int nId, Plugin plugin ) field.setIsSort( daoUtil.getBoolean( i++ ) ); field.setEnableSort( daoUtil.getBoolean( i++ ) ); field.setDefaultSort( daoUtil.getBoolean( i++ ) ); - field.setWeight( daoUtil.getDouble( i++ ) ); } daoUtil.free( ); @@ -172,7 +170,6 @@ public void store( Field field, Plugin plugin ) daoUtil.setBoolean( i++, field.getIsSort( ) ); daoUtil.setBoolean( i++, field.getEnableSort( ) ); daoUtil.setBoolean( i++, field.getDefaultSort( ) ); - daoUtil.setDouble(i++, field.getWeight()); daoUtil.setInt( i++, field.getIdField( ) ); daoUtil.executeUpdate( ); @@ -204,7 +201,6 @@ public List selectFieldsList( Plugin plugin ) field.setIsSort( daoUtil.getBoolean( i++ ) ); field.setEnableSort( daoUtil.getBoolean( i++ ) ); field.setDefaultSort( daoUtil.getBoolean( i++ ) ); - field.setWeight(daoUtil.getDouble( i++ ) ); fieldList.add( field ); } diff --git a/src/java/fr/paris/lutece/plugins/search/solr/business/field/SolrFieldManager.java b/src/java/fr/paris/lutece/plugins/search/solr/business/field/SolrFieldManager.java index ee3d5c8..1baa574 100644 --- a/src/java/fr/paris/lutece/plugins/search/solr/business/field/SolrFieldManager.java +++ b/src/java/fr/paris/lutece/plugins/search/solr/business/field/SolrFieldManager.java @@ -218,5 +218,4 @@ public String getQuery( ) return query; } } - } diff --git a/src/java/fr/paris/lutece/plugins/search/solr/indexer/SolrIndexerService.java b/src/java/fr/paris/lutece/plugins/search/solr/indexer/SolrIndexerService.java index b968021..e7d23b0 100644 --- a/src/java/fr/paris/lutece/plugins/search/solr/indexer/SolrIndexerService.java +++ b/src/java/fr/paris/lutece/plugins/search/solr/indexer/SolrIndexerService.java @@ -94,30 +94,94 @@ public static List getIndexers( ) } /** - * Index one document, called by plugin indexers + * Index one document without committing * @param solrItem The item + * @param sbLogs StringBuffer to write to * @throws CorruptIndexException corruptIndexException * @throws IOException i/o exception */ - public static void write( SolrItem solrItem ) throws CorruptIndexException, IOException + private static void writeNoCommit( SolrItem solrItem, StringBuffer sbLogs ) throws CorruptIndexException, IOException { try { SolrInputDocument solrInputDocument = solrItem2SolrInputDocument( solrItem ); SOLR_SERVER.add( solrInputDocument ); - SOLR_SERVER.commit( ); - _sbLogs.append( "Indexing " ); - _sbLogs.append( solrItem.getType( ) ); - _sbLogs.append( " #" ); - _sbLogs.append( solrItem.getUid( ) ); - _sbLogs.append( " - " ); - _sbLogs.append( solrItem.getTitle( ) ); - _sbLogs.append( "\r\n" ); + sbLogs.append( "Indexing " ); + sbLogs.append( solrItem.getType( ) ); + sbLogs.append( " #" ); + sbLogs.append( solrItem.getUid( ) ); + sbLogs.append( " - " ); + sbLogs.append( solrItem.getTitle( ) ); + sbLogs.append( "\r\n" ); } catch ( Exception e ) { - printIndexMessage( e ); + printIndexMessage( e, sbLogs ); + } + } + + /** + * Index one document, called by plugin indexers + * @param solrItem The item + * @throws CorruptIndexException corruptIndexException + * @throws IOException i/o exception + */ + public static void write( SolrItem solrItem ) throws CorruptIndexException, IOException + { + write( solrItem, _sbLogs ); + } + + /** + * Index one document, called by external code + * @param solrItem The item + * @param sbLogs StringBuffer to write to + * @throws CorruptIndexException corruptIndexException + * @throws IOException i/o exception + */ + public static void write( SolrItem solrItem, StringBuffer sbLogs ) throws CorruptIndexException, IOException + { + try + { + writeNoCommit( solrItem, sbLogs ); + SOLR_SERVER.commit( ); + } + catch ( Exception e ) + { + printIndexMessage( e, sbLogs ); + } + } + + /** + * Index a collection of documents, called by plugin indexers + * @param solrItems The item + * @throws CorruptIndexException corruptIndexException + * @throws IOException i/o exception + */ + public static void write( Collection solrItems ) throws CorruptIndexException, IOException + { + write( solrItems, _sbLogs ); + } + + /** + * Index a collection of documents, called by external code + * @param solrItems The item + * @param sbLogs StringBuffer to write to + * @throws CorruptIndexException corruptIndexException + * @throws IOException i/o exception + */ + public static void write( Collection solrItems, StringBuffer sbLogs ) throws CorruptIndexException, IOException + { + try + { + for ( SolrItem solrItem: solrItems ) { + writeNoCommit( solrItem, sbLogs ); + } + SOLR_SERVER.commit( ); + } + catch ( Exception e ) + { + printIndexMessage( e, sbLogs ); } } @@ -303,9 +367,9 @@ else if ( action.getIdTask( ) == IndexerAction.TASK_MODIFY ) { _sbLogs.append( " caught a " ); _sbLogs.append( e.getClass( ) ); - _sbLogs.append( "\n with message: " ); + _sbLogs.append( "\r\n with message: " ); _sbLogs.append( e.getMessage( ) ); - _sbLogs.append( "\r\n" ); + _sbLogs.append( "\r\n See error logs for the stacktrace.\r\n" ); AppLogService.error( "Indexing error : " + e.getMessage( ), e ); } @@ -354,21 +418,22 @@ public static List getAdditionalFields( ) } /** - * Adds the exception into the buffer and the logs + * Adds the exception into the buffer and the StringBuffer * @param exception Exception to report + * @param sbLogs StringBuffer to write to */ - private static void printIndexMessage( Exception exception ) + private static void printIndexMessage( Exception exception, StringBuffer sbLogs ) { - _sbLogs.append( " - ERROR : " ); - _sbLogs.append( exception.getMessage( ) ); + sbLogs.append( " - ERROR : " ); + sbLogs.append( exception.getMessage( ) ); if ( exception.getCause( ) != null ) { - _sbLogs.append( " : " ); - _sbLogs.append( exception.getCause( ).getMessage( ) ); + sbLogs.append( " : " ); + sbLogs.append( exception.getCause( ).getMessage( ) ); } - _sbLogs.append( "\r\n" ); + sbLogs.append( "\r\n" ); AppLogService.error( exception.getMessage( ), exception ); } @@ -441,10 +506,10 @@ private static List initIndexersList( ) } /** - * Return the url of the webapp + * Return the url of the Root of the webapp * @return strBase the webapp url */ - public static String getBaseUrl( ) + public static String getRootUrl( ) { String strBaseUrl = AppPropertiesService.getProperty( PROPERTY_BASE_URL ); @@ -453,10 +518,22 @@ public static String getBaseUrl( ) strBaseUrl = AppPropertiesService.getProperty( PROPERTY_PROD_URL ); } - if ( !strBaseUrl.endsWith( "/" ) ) + if ( !StringUtils.isBlank( strBaseUrl ) && !strBaseUrl.endsWith( "/" ) ) { strBaseUrl = strBaseUrl + "/"; } + + strBaseUrl = StringUtils.isBlank( strBaseUrl ) ? "" : strBaseUrl; + return strBaseUrl; + } + + /** + * Return the url of the Portal of the webapp (eg http://host/WEBAPP/jsp/site/Portal.jsp) + * @return strBase the webapp url + */ + public static String getBaseUrl( ) + { + String strBaseUrl = getRootUrl( ); return strBaseUrl + AppPathService.getPortalUrl( ); } @@ -474,25 +551,31 @@ public static String getWebAppName( ) * Del sorl index related to this site. * @return log of what appended */ - public static String processDel( ) + public static synchronized String processDel( ) { - String strLog = ""; + // String buffer for building the response page; + _sbLogs = new StringBuffer( ); String strSite = AppPropertiesService.getProperty( PROPERTY_SITE ); + _sbLogs.append("Delete site : " + strSite + "\r\n"); + AppLogService.info( _sbLogs.toString() ); + try { SOLR_SERVER.deleteByQuery( SolrItem.FIELD_SITE + ":\"" + strSite + "\"" ); SOLR_SERVER.commit( ); SOLR_SERVER.optimize( ); - strLog = "Delete site : " + strSite; - AppLogService.info( strLog ); } catch ( Exception e ) { AppLogService.error( "Erreur lors de la suppression de l'index solr", e ); - strLog = ( e.getCause( ) != null ? e.getCause( ).toString( ) : e.toString( ) ); + _sbLogs.append(( e.getCause( ) != null ? e.getCause( ).toString( ) : e.toString( ) ) + "\r\n"); } - return strLog; + return _sbLogs.toString(); + } + + public static StringBuffer getSbLogs() { + return _sbLogs; } } diff --git a/src/java/fr/paris/lutece/plugins/search/solr/indexer/SolrItem.java b/src/java/fr/paris/lutece/plugins/search/solr/indexer/SolrItem.java index a0b1a35..d8e9617 100644 --- a/src/java/fr/paris/lutece/plugins/search/solr/indexer/SolrItem.java +++ b/src/java/fr/paris/lutece/plugins/search/solr/indexer/SolrItem.java @@ -33,13 +33,22 @@ */ package fr.paris.lutece.plugins.search.solr.indexer; +import fr.paris.lutece.plugins.leaflet.business.GeolocItem; import fr.paris.lutece.portal.service.search.SearchItem; +import fr.paris.lutece.portal.service.util.AppLogService; import org.apache.solr.client.solrj.beans.Field; +import org.codehaus.jackson.JsonNode; +import org.codehaus.jackson.map.ObjectMapper; + +import java.io.IOException; +import java.util.Arrays; import java.util.Date; import java.util.HashMap; +import java.util.Iterator; import java.util.List; +import java.util.Locale; import java.util.Map; @@ -62,6 +71,11 @@ public class SolrItem public static final String DYNAMIC_DATE_FIELD_SUFFIX = "_date"; public static final String DYNAMIC_LONG_FIELD_SUFFIX = "_long"; public static final String DYNAMIC_LIST_FIELD_SUFFIX = "_list"; + public static final String DYNAMIC_GEOLOC_FIELD_SUFFIX = "_geoloc"; + public static final String DYNAMIC_GEOJSON_FIELD_SUFFIX = "_geojson"; + public static final String DYNAMIC_GEOJSON_ADDRESS_FIELD_SUFFIX = "_address"; + private static final String GEOLOC_JSON_PATH_GEOMETRY = "geometry"; + private static final String GEOLOC_JSON_PATH_GEOMETRY_COORDINATES = "coordinates"; @Field( SearchItem.FIELD_URL ) private String _strUrl; @Field( SearchItem.FIELD_DATE ) @@ -102,6 +116,10 @@ public class SolrItem private Map _dfDate; @Field( "*" + DYNAMIC_LONG_FIELD_SUFFIX ) private Map _dfNumericText; + @Field( "*" + DYNAMIC_GEOLOC_FIELD_SUFFIX ) + private Map _dfGeoloc; + @Field( "*" + DYNAMIC_GEOJSON_FIELD_SUFFIX ) + private Map _dfGeojson; /** * Creates a new SolrItem @@ -143,6 +161,16 @@ public Map getDynamicFields( ) mapDynamicFields.putAll( _dfText ); } + if ( _dfGeoloc != null ) + { + mapDynamicFields.putAll( _dfGeoloc ); + } + + if ( _dfGeojson != null ) + { + mapDynamicFields.putAll( _dfGeojson ); + } + return mapDynamicFields; } @@ -221,6 +249,142 @@ public void addDynamicFieldNotAnalysed( String strName, String strValue ) _dfString.put( strName + DYNAMIC_STRING_FIELD_SUFFIX, strValue ); } + /** + * Add a dynamic field + * @param strName the name of the field + * @param geolocItem a GeolocItem + * @param codeDocumentType the codeDocumentType + */ + public void addDynamicFieldGeoloc( String strName, GeolocItem geolocItem, String codeDocumentType ) { + if ( geolocItem.getIcon( ) == null ) + { + geolocItem.setIcon( codeDocumentType + "-" + strName ); + } + + List coordinates = geolocItem.getLonLat(); + if ( coordinates != null ) + { + if ( _dfGeoloc == null ) + { + _dfGeoloc = new HashMap( ); + } + + if ( _dfGeojson == null ) + { + _dfGeojson = new HashMap( ); + } + + String strCoordinates = String.format( Locale.ENGLISH, "%.6f,%.6f", coordinates.get(1), coordinates.get(0) ); + _dfGeoloc.put( strName + DYNAMIC_GEOLOC_FIELD_SUFFIX, strCoordinates ); + + _dfGeojson.put( strName + DYNAMIC_GEOJSON_FIELD_SUFFIX, geolocItem.toJSON( ) ); + + if (geolocItem.getAddress() != null) { + addDynamicField( strName + DYNAMIC_GEOJSON_ADDRESS_FIELD_SUFFIX , geolocItem.getAddress() ); + } + } + } + /** + * Add a dynamic field + * @param strName the name of the field + * @param strAdress the adress of the field + * @param dLongitude the longitude of the field + * @param dLatitude the latitude of the field + * @param codeDocumentType the codeDocumentType + */ + public void addDynamicFieldGeoloc( String strName, String strAdress, double dLongitude, double dLatitude, String codeDocumentType ) { + GeolocItem geolocItem = new GeolocItem(); + HashMap properties = new HashMap( ); + properties.put( GeolocItem.PATH_PROPERTIES_ADDRESS, strAdress ); + + HashMap geometry = new HashMap( ); + geometry.put( GeolocItem.PATH_GEOMETRY_COORDINATES, Arrays.asList( new Double[] { dLongitude, dLatitude } ) ); + geolocItem.setGeometry( geometry ); + geolocItem.setProperties( properties ); + addDynamicFieldGeoloc( strName, geolocItem, codeDocumentType ); + } + /** + * Add a dynamic field + * @param strName the name of the field + * @param strValue the value of the field which should be a geojson string + * @param codeDocumentType the codeDocumentType + */ + public void addDynamicFieldGeoloc( String strName, String strValue, String codeDocumentType ) + { + JsonNode object; + + try + { + object = new ObjectMapper( ).readTree( strValue ); + } + catch ( IOException e ) + { + AppLogService.error( "SolrItem: exception during GEOJSON parsing : " + strValue + " : " + e ); + + return; + } + + JsonNode objCoordinates = object.path( GEOLOC_JSON_PATH_GEOMETRY ).path( GEOLOC_JSON_PATH_GEOMETRY_COORDINATES ); + + if ( objCoordinates.isMissingNode( ) ) + { + AppLogService.error( "SolrItem: missing coordinates : " + strValue ); + } + else + { + if ( !objCoordinates.isArray( ) ) + { + AppLogService.error( "SolrItem: coordinates not an array : " + strValue ); + } + else + { + double[] parsedCoordinates = new double[2]; + Iterator it = objCoordinates.getElements( ); + boolean bCoordinatesOk = true; + + for ( int i = 0; i < parsedCoordinates.length; i++ ) + { + if ( !it.hasNext( ) ) + { + AppLogService.error( "SolrItem: coordinates array too short : " + strValue + " at element " + + Integer.toString( i ) ); + bCoordinatesOk = false; + + break; + } + + JsonNode node = it.next( ); + + if ( !node.isNumber( ) ) + { + AppLogService.error( "SolrItem: coordinate not a number : " + strValue + " at element " + + Integer.toString( i ) ); + bCoordinatesOk = false; + + break; + } + + parsedCoordinates[i] = node.asDouble( ); + } + + } + } + + GeolocItem geolocItem = null; + + try + { + geolocItem = GeolocItem.fromJSON( strValue ); + } + catch ( IOException e ) + { + AppLogService.error( "SolrItem: Error parsing JSON: " + strValue + "exception: " + e ); + } + if ( geolocItem != null ) { + addDynamicFieldGeoloc(strName, geolocItem, codeDocumentType); + } + } + /** * Gets the url * @return the url diff --git a/src/java/fr/paris/lutece/plugins/search/solr/service/ISolrSearchAppAddOn.java b/src/java/fr/paris/lutece/plugins/search/solr/service/ISolrSearchAppAddOn.java new file mode 100644 index 0000000..6abf693 --- /dev/null +++ b/src/java/fr/paris/lutece/plugins/search/solr/service/ISolrSearchAppAddOn.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2002-2015, Mairie de Paris + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright notice + * and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice + * and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * License 1.0 + */ +package fr.paris.lutece.plugins.search.solr.service; + +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +/** +* +*Interface ISolrSearchAppAddOn : add data to SolrSearchApp's model +* +*/ +public interface ISolrSearchAppAddOn { + + /** + * Add datas to the model used by SolrSearchApp template + * + * @param model The model use by document template + * @param request The HTTP Request + */ + void buildPageAddOn( Map model, HttpServletRequest request ); +} diff --git a/src/java/fr/paris/lutece/plugins/search/solr/service/SolrSearchAppConfService.java b/src/java/fr/paris/lutece/plugins/search/solr/service/SolrSearchAppConfService.java new file mode 100644 index 0000000..98cf9c1 --- /dev/null +++ b/src/java/fr/paris/lutece/plugins/search/solr/service/SolrSearchAppConfService.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2002-2015, Mairie de Paris + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright notice + * and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice + * and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * License 1.0 + */ +package fr.paris.lutece.plugins.search.solr.service; + +import java.util.List; + +import fr.paris.lutece.plugins.search.solr.business.SolrSearchAppConf; +import fr.paris.lutece.plugins.search.solr.util.SolrConstants; +import fr.paris.lutece.portal.service.datastore.DatastoreService; +import fr.paris.lutece.util.ReferenceItem; +import fr.paris.lutece.util.ReferenceList; + + +/** + * + * SolrSearchApp + * + */ +public class SolrSearchAppConfService +{ + public static final String EMPTY_CODE = ""; + private static final String DSKEY_PREFIX = "solr.app.conf."; + private static final String DSKEY_INSTALLED = ".installed"; + private static final String DSKEY_FQ = ".fq"; + private static final String DSKEY_TEMPLATE = ".template"; + private static final String DSKEY_MAPPING = ".mapping"; + private static final String DSKEY_ADDON_BEANS = ".addonBeans."; + + public static SolrSearchAppConf loadConfiguration( String code ) + { + String strSafeCode = ( code == null ) ? EMPTY_CODE : code; + String strPrefix = DSKEY_PREFIX + strSafeCode ; + ReferenceList referenceList = DatastoreService.getDataByPrefix( strPrefix + "."); + + if ( referenceList.isEmpty( ) && !EMPTY_CODE.equals( strSafeCode ) ) + { + return null; + } + + SolrSearchAppConf conf = new SolrSearchAppConf( ); + conf.setCode( strSafeCode ); + + String strAddonPrefix = strPrefix + DSKEY_ADDON_BEANS; + for ( ReferenceItem referenceItem : referenceList ) + { + String referenceItemCode = referenceItem.getCode( ); + String referenceItemName = referenceItem.getName( ); + if ( referenceItemCode.endsWith( DSKEY_FQ ) ) + { + conf.setFilterQuery( referenceItemName ); + } + else if ( referenceItemCode.endsWith( DSKEY_TEMPLATE ) ) + { + conf.setTemplate( referenceItemName ); + } + else if ( referenceItemCode.endsWith( DSKEY_MAPPING ) ) + { + conf.setExtraMappingQuery( SolrConstants.CONSTANT_TRUE.equals( referenceItemName ) ); + } + else if ( referenceItemCode.startsWith( strAddonPrefix ) ) + { + conf.getAddonBeanNames().add ( referenceItemName ); + } + } + + return conf; + } + + public static void saveConfiguration( SolrSearchAppConf conf ) + { + String strSafeCode = ( conf.getCode( ) != null ) ? conf.getCode( ) : EMPTY_CODE; + String strPrefix = DSKEY_PREFIX + strSafeCode; + DatastoreService.setDataValue( strPrefix + DSKEY_INSTALLED, SolrConstants.CONSTANT_TRUE ); + DatastoreService.setDataValue( strPrefix + DSKEY_FQ, conf.getFilterQuery( ) ); + DatastoreService.setDataValue( strPrefix + DSKEY_TEMPLATE, conf.getTemplate( ) ); + DatastoreService.setDataValue( strPrefix + DSKEY_MAPPING, + conf.getExtraMappingQuery( ) ? SolrConstants.CONSTANT_TRUE : SolrConstants.CONSTANT_FALSE ); + List listAddonBeanNames = conf.getAddonBeanNames(); + for ( int i = 0; i < listAddonBeanNames.size(); i++ ) { + DatastoreService.setDataValue( strPrefix + DSKEY_ADDON_BEANS + i , listAddonBeanNames.get( i ) ); + } + } +} diff --git a/src/java/fr/paris/lutece/plugins/search/solr/util/SolrConstants.java b/src/java/fr/paris/lutece/plugins/search/solr/util/SolrConstants.java index 1f9efb8..951225d 100644 --- a/src/java/fr/paris/lutece/plugins/search/solr/util/SolrConstants.java +++ b/src/java/fr/paris/lutece/plugins/search/solr/util/SolrConstants.java @@ -44,4 +44,8 @@ public class SolrConstants public static final String CONSTANT_COLON = ":"; public static final String CONSTANT_QUOTE = "\""; public static final String CONSTANT_TRUE = "true"; + public static final String CONSTANT_FALSE = "false"; + public static final String CONSTANT_DEFAULT_TEMPLATE = "skin/search/solr_search_results.html"; + public static final String CONSTANT_DEFAULT_FILTER_QUERY = ""; + public static final boolean CONSTANT_DEFAULT_EXTRA_MAPPING_QUERY = false; } diff --git a/src/java/fr/paris/lutece/plugins/search/solr/web/SolrFieldsManagementJspBean.java b/src/java/fr/paris/lutece/plugins/search/solr/web/SolrFieldsManagementJspBean.java index ada76a3..87b251e 100644 --- a/src/java/fr/paris/lutece/plugins/search/solr/web/SolrFieldsManagementJspBean.java +++ b/src/java/fr/paris/lutece/plugins/search/solr/web/SolrFieldsManagementJspBean.java @@ -166,7 +166,6 @@ public String doUpdateField( HttpServletRequest request ) field.setIsFacet( request.getParameter( "isfacet" ) != null ); field.setIsSort( request.getParameter( "issort" ) != null ); - field.setWeight( Double.parseDouble(request.getParameter( "weight" ) )); FieldHome.update( field ); SolrFieldManager.reloadField( ); @@ -194,7 +193,6 @@ public String doCreateField( HttpServletRequest request ) field.setIsSort( request.getParameter( "issort" ) != null ); field.setEnableSort( false ); field.setDefaultSort( false ); - field.setWeight( Double.parseDouble(request.getParameter( "weight" ) )); FieldHome.create( field ); SolrFieldManager.reloadField( ); diff --git a/src/java/fr/paris/lutece/plugins/search/solr/web/SolrIndexerJspBean.java b/src/java/fr/paris/lutece/plugins/search/solr/web/SolrIndexerJspBean.java index d3708e9..beb9e83 100644 --- a/src/java/fr/paris/lutece/plugins/search/solr/web/SolrIndexerJspBean.java +++ b/src/java/fr/paris/lutece/plugins/search/solr/web/SolrIndexerJspBean.java @@ -35,10 +35,12 @@ import fr.paris.lutece.plugins.search.solr.indexer.SolrIndexerService; import fr.paris.lutece.portal.service.template.AppTemplateService; +import fr.paris.lutece.portal.service.util.AppLogService; import fr.paris.lutece.portal.web.admin.PluginAdminPageJspBean; import fr.paris.lutece.util.html.HtmlTemplate; import java.util.HashMap; +import java.util.Map; import javax.servlet.http.HttpServletRequest; @@ -56,8 +58,35 @@ public class SolrIndexerJspBean extends PluginAdminPageJspBean private static final String TEMPLATE_MANAGE_INDEXER = "admin/search/solr_manage_search_indexation.html"; private static final String TEMPLATE_INDEXER_LOGS = "admin/search/solr_search_indexation_logs.html"; private static final String MARK_LOGS = "logs"; + private static final String MARK_RUNNING = "running"; + private static final String MARK_COMMAND = "command"; private static final String MARK_INDEXERS_LIST = "indexers_list"; + private static final String JSP_VIEW_INDEXATION = "ViewSearchIndexation.jsp"; + + private static Thread _thread; + private static String _threadLogs; + private static String _command; + + private Map getModel() { + Map model = new HashMap<>(); + + String strLogs; + boolean bRunning; + if (_thread != null) { + strLogs = SolrIndexerService.getSbLogs().toString(); + bRunning = true; + } else { + strLogs = _threadLogs; + bRunning = false; + } + + model.put( MARK_LOGS, strLogs ); + model.put( MARK_RUNNING, bRunning ); + model.put( MARK_COMMAND, _command ); + return model; + } + /** * Displays the indexing parameters * @@ -66,7 +95,7 @@ public class SolrIndexerJspBean extends PluginAdminPageJspBean */ public String getIndexingProperties( HttpServletRequest request ) { - HashMap model = new HashMap( ); + Map model = getModel(); model.put( MARK_INDEXERS_LIST, SolrIndexerService.getIndexers( ) ); HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_MANAGE_INDEXER, getLocale( ), model ); @@ -75,33 +104,68 @@ public String getIndexingProperties( HttpServletRequest request ) } /** - * Calls the indexing process + * Displays the indexation progress * * @param request the http request - * @return the result of the indexing process + * @return the html code which displays the parameters page */ - public String doIndexing( HttpServletRequest request ) + public String getIndexing( HttpServletRequest request ) { - HashMap model = new HashMap( ); - String strLogs = ""; + Map model = getModel(); - if ( request.getParameter( "incremental" ) != null ) - { - strLogs = SolrIndexerService.processIndexing( false ); - } - else if ( request.getParameter( "total" ) != null ) - { - strLogs = SolrIndexerService.processIndexing( true ); - } - else if ( request.getParameter( "del" ) != null ) - { - strLogs = SolrIndexerService.processDel( ); - } + HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_INDEXER_LOGS, getLocale( ), model ); - model.put( MARK_LOGS, strLogs ); + return getAdminPage( template.getHtml( ) ); + } - HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_INDEXER_LOGS, null, model ); + /** + * Calls the indexing process + * + * @param request the http request + * @return the result of the indexing process + */ + public static synchronized String doIndexing( HttpServletRequest request ) + { + if (_thread == null) { + if ( request.getParameter( "incremental" ) != null ) + { + _command = "incremental"; + } + else if ( request.getParameter( "total" ) != null ) + { + _command = "total"; + } + else if ( request.getParameter( "del" ) != null ) + { + _command = "del"; + } + _thread = new Thread() { + @Override + public void run() { + try { + if ( "incremental".equals(_command) ) + { + _threadLogs = SolrIndexerService.processIndexing( false ); + } + else if ( "total".equals(_command) ) + { + _threadLogs = SolrIndexerService.processIndexing( true ); + } + else if ( "del".equals(_command) ) + { + _threadLogs = SolrIndexerService.processDel( ); + } + } catch (Exception e) { + _threadLogs = e.toString(); + AppLogService.error ("Error during solr indexation", e ); + } finally { + _thread = null; + } + } + }; + _thread.start(); + } - return getAdminPage( template.getHtml( ) ); + return JSP_VIEW_INDEXATION; } } diff --git a/src/java/fr/paris/lutece/plugins/search/solr/web/SolrSearchApp.java b/src/java/fr/paris/lutece/plugins/search/solr/web/SolrSearchApp.java index 543c272..0ba4cb9 100644 --- a/src/java/fr/paris/lutece/plugins/search/solr/web/SolrSearchApp.java +++ b/src/java/fr/paris/lutece/plugins/search/solr/web/SolrSearchApp.java @@ -33,10 +33,16 @@ */ package fr.paris.lutece.plugins.search.solr.web; +import fr.paris.lutece.plugins.leaflet.business.GeolocItem; +import fr.paris.lutece.plugins.leaflet.service.IconService; import fr.paris.lutece.plugins.search.solr.business.SolrFacetedResult; +import fr.paris.lutece.plugins.search.solr.business.SolrSearchAppConf; import fr.paris.lutece.plugins.search.solr.business.SolrSearchEngine; import fr.paris.lutece.plugins.search.solr.business.SolrSearchResult; import fr.paris.lutece.plugins.search.solr.business.field.SolrFieldManager; +import fr.paris.lutece.plugins.search.solr.indexer.SolrItem; +import fr.paris.lutece.plugins.search.solr.service.ISolrSearchAppAddOn; +import fr.paris.lutece.plugins.search.solr.service.SolrSearchAppConfService; import fr.paris.lutece.plugins.search.solr.util.SolrConstants; import fr.paris.lutece.plugins.search.solr.util.SolrUtil; import fr.paris.lutece.portal.service.i18n.I18nService; @@ -44,6 +50,7 @@ import fr.paris.lutece.portal.service.plugin.Plugin; import fr.paris.lutece.portal.service.search.QueryEvent; import fr.paris.lutece.portal.service.search.QueryListenersService; +import fr.paris.lutece.portal.service.spring.SpringContextService; import fr.paris.lutece.portal.service.template.AppTemplateService; import fr.paris.lutece.portal.service.util.AppLogService; import fr.paris.lutece.portal.service.util.AppPropertiesService; @@ -55,6 +62,7 @@ import fr.paris.lutece.util.html.Paginator; import fr.paris.lutece.util.string.StringUtil; import fr.paris.lutece.util.url.UrlItem; +import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -77,7 +85,6 @@ public class SolrSearchApp implements XPageApplication //////////////////////////////////////////////////////////////////////////// // Constants - private static final String TEMPLATE_RESULTS = "skin/search/solr_search_results.html"; private static final String PROPERTY_SEARCH_PAGE_URL = "solr.pageSearch.baseUrl"; private static final String PROPERTY_RESULTS_PER_PAGE = "search.nb.docs.per.page"; private static final String PROPERTY_PATH_LABEL = "portal.search.search_results.pathLabel"; @@ -92,6 +99,7 @@ public class SolrSearchApp implements XPageApplication private static final String PARAMETER_PAGE_INDEX = "page_index"; private static final String PARAMETER_NB_ITEMS_PER_PAGE = "items_per_page"; private static final String PARAMETER_QUERY = "query"; + private static final String PARAMETER_CONF = "conf"; private static final String PARAMETER_FACET_QUERY = "fq"; private static final String PARAMETER_PREVIOUS_SEARCH = "previous_search"; @@ -116,6 +124,13 @@ public class SolrSearchApp implements XPageApplication private static final String MARK_FACET_TREE = "facet_tree"; private static final String MARK_FACETS_LIST = "facets_list"; private static final String MARK_ENCODING = "encoding"; + private static final String MARK_CONF_QUERY = "conf_user_query"; + private static final String MARK_CONF = "conf"; + private static final String MARK_POINTS = "points"; + private static final String MARK_POINTS_GEOJSON = "geojson"; + private static final String MARK_POINTS_ID = "id"; + private static final String MARK_POINTS_FIELDCODE = "code"; + private static final String MARK_POINTS_TYPE = "type"; private static final String PROPERTY_ENCODE_URI = "search.encode.uri"; private static final boolean DEFAULT_ENCODE_URI = false; private static final boolean SOLR_SPELLCHECK = AppPropertiesService.getPropertyBoolean("solr.spellchecker", false); @@ -134,9 +149,22 @@ public XPage getPage(HttpServletRequest request, int nMode, Plugin plugin) throws SiteMessageException { XPage page = new XPage(); - Map model = getSearchResultModel(request); - HtmlTemplate template = AppTemplateService.getTemplate(TEMPLATE_RESULTS, request.getLocale(), model); + String strConfCode = request.getParameter( PARAMETER_CONF ); + SolrSearchAppConf conf = SolrSearchAppConfService.loadConfiguration( strConfCode ); + if ( conf == null ) + { + //Use default conf if the requested one doesn't exist + conf = SolrSearchAppConfService.loadConfiguration( null ); + } + + Map model = getSearchResultModel(request, conf); + for ( String beanName: conf.getAddonBeanNames() ) { + ISolrSearchAppAddOn solrSearchAppAddon = SpringContextService.getBean( beanName ); + solrSearchAppAddon.buildPageAddOn( model, request ); + } + + HtmlTemplate template = AppTemplateService.getTemplate(conf.getTemplate(), request.getLocale(), model); page.setPathLabel(I18nService.getLocalizedString(PROPERTY_PATH_LABEL, request.getLocale())); page.setTitle(I18nService.getLocalizedString(PROPERTY_PAGE_TITLE, request.getLocale())); @@ -147,7 +175,7 @@ public XPage getPage(HttpServletRequest request, int nMode, Plugin plugin) /** * Performs a search and fills the model (useful when a page needs to remind - * search parameters/results) + * search parameters/results) with the default conf * * @param request the request * @return the model @@ -155,14 +183,36 @@ public XPage getPage(HttpServletRequest request, int nMode, Plugin plugin) */ public static Map getSearchResultModel(HttpServletRequest request) throws SiteMessageException + { + return getSearchResultModel(request, null); + } + + /** + * Performs a search and fills the model (useful when a page needs to remind + * search parameters/results) + * + * @param request the request + * @param conf the configuration + * @return the model + * @throws SiteMessageException if an error occurs + */ + public static Map getSearchResultModel(HttpServletRequest request, SolrSearchAppConf conf) + throws SiteMessageException { String strQuery = request.getParameter(PARAMETER_QUERY); String[] facetQuery = request.getParameterValues(PARAMETER_FACET_QUERY); String sort = request.getParameter(PARAMETER_SORT_NAME); String order = request.getParameter(PARAMETER_SORT_ORDER); String strCurrentPageIndex = request.getParameter(PARAMETER_PAGE_INDEX); + String strConfCode = request.getParameter( PARAMETER_CONF ); Locale locale = request.getLocale(); + if ( conf == null ) + { + //Use default conf if not provided + conf = SolrSearchAppConfService.loadConfiguration( null ); + } + //String facetlabel = request.getParameter( PARAMETER_FACET_LABEL ); //String facetname = request.getParameter( PARAMETER_FACET_NAME ); StringBuilder sbFacetQueryUrl = new StringBuilder(); @@ -183,6 +233,20 @@ public static Map getSearchResultModel(HttpServletRequest reques } } + if ( StringUtils.isNotBlank( conf.getFilterQuery( ) ) ) + { + int nNewLength = ( facetQuery == null ) ? 1 : ( facetQuery.length + 1 ); + String[] newFacetQuery = new String[nNewLength]; + + for ( int i = 0; i < ( nNewLength - 1 ); i++ ) + { + newFacetQuery[i] = facetQuery[i]; + } + + newFacetQuery[newFacetQuery.length - 1] = conf.getFilterQuery( ); + facetQuery = newFacetQuery; + } + boolean bEncodeUri = Boolean.parseBoolean(AppPropertiesService.getProperty(PROPERTY_ENCODE_URI, Boolean.toString(DEFAULT_ENCODE_URI))); @@ -222,9 +286,16 @@ public static Map getSearchResultModel(HttpServletRequest reques strCurrentPageIndex = (strCurrentPageIndex != null) ? strCurrentPageIndex : DEFAULT_PAGE_INDEX; SolrSearchEngine engine = SolrSearchEngine.getInstance(); - SolrFacetedResult facetedResult = engine.getFacetedSearchResults(strQuery, facetQuery, sort, order, nLimit, Integer.parseInt(strCurrentPageIndex), nItemsPerPage, SOLR_SPELLCHECK); + SolrFacetedResult facetedResult = engine.getFacetedSearchResults(strQuery, facetQuery, sort, order, nLimit, Integer.parseInt(strCurrentPageIndex), nItemsPerPage); List listResults = facetedResult.getSolrSearchResults(); + List> points = null; + if ( conf.getExtraMappingQuery( ) ) + { + List listResultsGeoloc = engine.getGeolocSearchResults( strQuery, facetQuery, nLimit ); + points = getGeolocModel(listResultsGeoloc); + } + // The page should not be added to the cache // Notify results infos to QueryEventListeners notifyQueryListeners(strQuery, listResults.size(), request); @@ -240,6 +311,11 @@ public static Map getSearchResultModel(HttpServletRequest reques url.addParameter(PARAMETER_QUERY, strQueryForPaginator); url.addParameter(PARAMETER_NB_ITEMS_PER_PAGE, nItemsPerPage); + if ( strConfCode != null ) + { + url.addParameter( PARAMETER_CONF, strConfCode ); + } + for (String strFacetName : lstSingleFacetQueries) { url.addParameter(PARAMETER_FACET_QUERY, SolrUtil.encodeUrl(strFacetName)); @@ -262,6 +338,9 @@ public static Map getSearchResultModel(HttpServletRequest reques model.put(MARK_FACETS_DATE, facetedResult.getFacetDateList()); model.put(MARK_HISTORIQUE, sfm.getCurrentFacet()); model.put(MARK_FACETS_LIST, lstSingleFacetQueries); + model.put( MARK_CONF_QUERY, strConfCode ); + model.put( MARK_CONF, conf ); + model.put( MARK_POINTS, points ); if (SOLR_SPELLCHECK && (strQuery != null) && (strQuery.compareToIgnoreCase(ALL_SEARCH_QUERY) != 0)) { @@ -269,7 +348,7 @@ public static Map getSearchResultModel(HttpServletRequest reques if (checkResponse != null) { - model.put(MARK_SUGGESTION, facetedResult.getSolrSpellCheckResponse().getCollatedResults()); + model.put(MARK_SUGGESTION, checkResponse.getCollatedResult()); } } @@ -286,6 +365,68 @@ public static Map getSearchResultModel(HttpServletRequest reques return model; } + /** + * Returns a model with points data from a geoloc search + * @param listResultsGeoloc the result of a search + * @return the model + */ + private static List> getGeolocModel( List listResultsGeoloc ) { + List> points = new ArrayList>( listResultsGeoloc.size( ) ); + HashMap iconKeysCache = new HashMap( ); + + for ( SolrSearchResult result : listResultsGeoloc ) + { + Map dynamicFields = result.getDynamicFields( ); + + for ( String key : dynamicFields.keySet( ) ) + { + if ( key.endsWith( SolrItem.DYNAMIC_GEOJSON_FIELD_SUFFIX ) ) + { + HashMap h = new HashMap( ); + String strJson = (String) dynamicFields.get( key ); + GeolocItem geolocItem = null; + + try + { + geolocItem = GeolocItem.fromJSON( strJson ); + } + catch ( IOException e ) + { + AppLogService.error( "SolrSearchApp: error parsing geoloc JSON: " + strJson + + ", exception " + e ); + } + + if ( geolocItem != null ) + { + String strType = result.getId( ).substring( result.getId( ).lastIndexOf( "_" ) + 1 ); + String strIcon; + + if ( iconKeysCache.containsKey( geolocItem.getIcon( ) ) ) + { + strIcon = iconKeysCache.get( geolocItem.getIcon( ) ); + } + else + { + strIcon = IconService.getIcon( strType, geolocItem.getIcon( ) ); + iconKeysCache.put( geolocItem.getIcon( ), strIcon ); + } + + geolocItem.setIcon( strIcon ); + h.put( MARK_POINTS_GEOJSON, geolocItem.toJSON( ) ); + h.put( MARK_POINTS_ID, + result.getId( ) + .substring( result.getId( ).indexOf( "_" ) + 1, + result.getId( ).lastIndexOf( "_" ) ) ); + h.put( MARK_POINTS_FIELDCODE, key.substring( 0, key.lastIndexOf( "_" ) ) ); + h.put( MARK_POINTS_TYPE, strType ); + points.add( h ); + } + } + } + } + return points; + } + /** * Notify all query Listeners * diff --git a/src/java/fr/paris/lutece/plugins/search/solr/web/SolrSuggestServlet.java b/src/java/fr/paris/lutece/plugins/search/solr/web/SolrSuggestServlet.java index a13402d..3f60801 100644 --- a/src/java/fr/paris/lutece/plugins/search/solr/web/SolrSuggestServlet.java +++ b/src/java/fr/paris/lutece/plugins/search/solr/web/SolrSuggestServlet.java @@ -36,7 +36,6 @@ import fr.paris.lutece.plugins.search.solr.business.SolrSearchEngine; import org.apache.solr.client.solrj.response.QueryResponse; -import org.apache.solr.client.solrj.response.SpellCheckResponse.Collation; import org.apache.solr.client.solrj.response.SpellCheckResponse.Suggestion; import java.io.IOException; @@ -81,39 +80,36 @@ public String getSuggest( HttpServletRequest request ) result.append( "({\"response\":{\"docs\":[" ); QueryResponse response = engine.getJsonpSuggest( terms, callback ); - Collation solr = null; + Suggestion solr = null; //String fieldName = null; - //int i= 1; + int i= 1; //Iterate on all document - for ( Iterator ite = response.getSpellCheckResponse().getCollatedResults().iterator(); ite.hasNext( ); ) + for ( Iterator ite = response.getSpellCheckResponse().getSuggestions().iterator(); ite.hasNext( ); ) { - if (ite.hasNext( )) - { - solr = ite.next( ); - - String collation=solr.getCollationQueryString(); - - - //iterate on each field - //for ( String suggest : suggestions ) - //{ - result.append( "{" ); - result.append( "\"" ).append( "title" ).append( "\":\"" ).append( collation ) - .append( "\"" ); - - - if ( ite.hasNext( ) ) - { - result.append( "}," ); - } - else - { - result.append( "}" ); - } - } - // i++; - //} + solr = ite.next( ); + + List suggestions=solr.getAlternatives(); + + + //iterate on each field + for ( String suggest : suggestions ) + { + result.append( "{" ); + result.append( "\"" ).append( "title" ).append( "\":\"" ).append( suggest ) + .append( "\"" ); + + + if ( suggestions.size() > i ) + { + result.append( "}," ); + } + else + { + result.append( "}" ); + } + i++; + } } //Close result diff --git a/src/site/fr/xdoc/index.xml b/src/site/fr/xdoc/index.xml index b5325ae..829afef 100644 --- a/src/site/fr/xdoc/index.xml +++ b/src/site/fr/xdoc/index.xml @@ -25,7 +25,7 @@

- Configuration a ajouter au solrconfig.xml + Configuration à ajouter au solrconfig.xml

     <requestHandler name="autoComplete" class="solr.SearchHandler">
@@ -49,6 +49,17 @@ http://dev.lutece.paris.fr/svn/lutece/contribs/atoswordline/trunk/config-SOLR/ex
 http://dev.lutece.paris.fr/svn/lutece/portal/trunk/plugins/technical/plugin-solrserver/webapp/WEB-INF/plugins/solrserver/conf/schema.xml
             

+ + +

Sur la xpage search-solr, on peut utiliser des configurations différentes en ajoutant le parametre de query "conf=XXX". Les configurations ont les parametres suivants:

+
    +
  • mapping: affiche ou non une carte montrant les documents géolocalisés
  • +
  • fq: applique des filtres coté serveur en plus de ceux de la requète
  • +
  • template: definit le template freemarker à utiliser à la place du template par défaut "skin/search/solr_search_results.html"
  • +
  • addonBeans.X: utilise des beans spring implémentant l'interface ISolrSearchAppAddOn pour ajouter des données au modèle freemarker. Plusieurs beans peuvent être utilisés en donnant plusieurs valeurs à ce paramètre avec différentes valeurs pour "X" (par convention "0", "1" ...)
  • +
+

Pour créer et éditer les configurations, il suffit d'insérer ou de modifier des clefs du datastore: solr.app.conf.XXX.YYY où XXX est le nom de la configuration qui sera utilisé dans l'URL de la xpage, et YYY le nom du paramètre à modifier. Par convention, on ajoute aussi la clef datastore solr.app.conf.XXX.installed avec la valeur "true"

+
- \ No newline at end of file + diff --git a/src/site/xdoc/index.xml b/src/site/xdoc/index.xml index 0e95315..852a049 100644 --- a/src/site/xdoc/index.xml +++ b/src/site/xdoc/index.xml @@ -29,8 +29,19 @@ </html>
+ + +

Different configurations can be applied to the xpage by using the query parameter "conf=XXX". Configurations have the following parameters:

+
    +
  • mapping: display results on a map
  • +
  • fq: apply extra filters on the server
  • +
  • template: set the freemarker template to use instead of the default "skin/search/solr_search_results.html"
  • +
  • addonBeans.X: use spring beans implementing the ISolrSearchAppAddOn interface to add data to the freemarker model. Multiple beans can be used by specifying multiple values for this parameter with different values of "X" (by convention, "0", "1" ...)
  • +
+

To add or edit configuration, insert datastore keys in the form: solr.app.conf.XXX.YYY where XXX is the name of the configuration (the query parameter of the xpage), and YYY the parameter the previous list to modify. By convention, also add a key "solr.app.conf.XXX.installed" with the value "true".

+
- \ No newline at end of file + diff --git a/src/sql/plugins/solr/upgrade/update_db_solr_3.0.0-3.0.1.sql b/src/sql/plugins/solr/upgrade/update_db_solr_3.0.0-3.0.1.sql deleted file mode 100644 index 97d78b9..0000000 --- a/src/sql/plugins/solr/upgrade/update_db_solr_3.0.0-3.0.1.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE solr_fields ADD weight float DEFAULT 1; diff --git a/webapp/WEB-INF/conf/plugins/search-solr.properties b/webapp/WEB-INF/conf/plugins/search-solr.properties index 2eb43c8..2a8842a 100644 --- a/webapp/WEB-INF/conf/plugins/search-solr.properties +++ b/webapp/WEB-INF/conf/plugins/search-solr.properties @@ -1,5 +1,9 @@ # server address +# Example for External Solr solr.server.address=http://localhost:8983/solr/ +# Example for Embedded Solr using lutece-search-plugin-solrserver +#solr.server.address=http://localhost:8080/lutece/solrserver/solr + # maximum connections opened by the solr client. Leave empty to use default. solr.server.max.connection=50 # timeout in milliseconds @@ -26,10 +30,7 @@ search.nb.docs.per.page=20 solr.spellchecker=false # max number of facets by facets types solr.facet.limit=100 - -#autocomplete and spellcheck handler name : the autocomplete and spellcheck handler name configured in solrconfig.xml -solr.autocomplete.handler=suggest -solr.autocomplete.handler=suggest +solr.facet.minCount=0 # daemon solr.daemon.indexer.incremental=true diff --git a/webapp/WEB-INF/plugins/solr.xml b/webapp/WEB-INF/plugins/solr.xml index 24ef1a4..c6eb062 100644 --- a/webapp/WEB-INF/plugins/solr.xml +++ b/webapp/WEB-INF/plugins/solr.xml @@ -3,7 +3,7 @@ solr fr.paris.lutece.plugins.search.solr.service.SolrPlugin - 3.0.1-SNAPSHOT + 3.0.4-SNAPSHOT @@ -59,19 +59,6 @@ - - - xpage - solr/jquery-1.10.2.min.js - solr/jquery-ui.min.js - - - - - xpage - solr/jquery-ui.css - - solrindexer @@ -81,4 +68,4 @@ - + \ No newline at end of file diff --git a/webapp/WEB-INF/templates/admin/search/solr_manage_fields_display.html b/webapp/WEB-INF/templates/admin/search/solr_manage_fields_display.html index acc766f..b993dfc 100644 --- a/webapp/WEB-INF/templates/admin/search/solr_manage_fields_display.html +++ b/webapp/WEB-INF/templates/admin/search/solr_manage_fields_display.html @@ -7,7 +7,6 @@

#i18n{search.solr.adminFeature.fields.display.title}

#i18n{search.solr.adminFeature.fields.form.label} #i18n{search.solr.adminFeature.fields.form.facet} #i18n{search.solr.adminFeature.fields.form.sort} - #i18n{search.solr.adminFeature.fields.form.weight} #i18n{search.solr.adminFeature.fields.form.description} #i18n{search.solr.adminFeature.fields.form.actions} <#list field_list as field> @@ -16,16 +15,6 @@

#i18n{search.solr.adminFeature.fields.display.title}

${field.label} ${field.isFacet?string} ${field.isSort?string} - - <#if field.weight == 0.1> - #i18n{search.solr.adminFeature.fields.form.weight.low} - <#elseif field.weight == 1> - #i18n{search.solr.adminFeature.fields.form.weight.normal} - <#else> - #i18n{search.solr.adminFeature.fields.form.weight.high} - - - ${field.description}
diff --git a/webapp/WEB-INF/templates/admin/search/solr_manage_fields_form.html b/webapp/WEB-INF/templates/admin/search/solr_manage_fields_form.html index f9ad5b6..a60e066 100644 --- a/webapp/WEB-INF/templates/admin/search/solr_manage_fields_form.html +++ b/webapp/WEB-INF/templates/admin/search/solr_manage_fields_form.html @@ -6,7 +6,7 @@

#i18n{search.solr.adminFeature.fields.form.create.title}

#i18n{search.solr.adminFeature.fields.form.update.title}


- +
@@ -41,16 +41,6 @@

#i18n{search.solr.adminFeature.fields.form.update.title}

-
- -
- -
-
diff --git a/webapp/WEB-INF/templates/admin/search/solr_manage_search_indexation.html b/webapp/WEB-INF/templates/admin/search/solr_manage_search_indexation.html index c9904a5..d9c5203 100644 --- a/webapp/WEB-INF/templates/admin/search/solr_manage_search_indexation.html +++ b/webapp/WEB-INF/templates/admin/search/solr_manage_search_indexation.html @@ -1,4 +1,5 @@
+

#i18n{portal.search.manage_indexer.labelIndexersList}

@@ -23,6 +24,39 @@

#i18n{portal.search.manage_indexer.labelIndexersList}


+<#if running?? && running> +

+   #i18n{search.solr.adminFeature.operationInProgress} : + <#if command = "del"> + #i18n{search.solr.adminFeature.buttonDoDel} + <#elseif command = "total"> + #i18n{portal.search.manage_indexer.buttonDoIndex} + <#elseif command = "incremental" > + #i18n{portal.search.manage_indexer.buttonDoIncrementalIndex} + <#else> + ${command} + ... +

+
+    ${logs}
+    
+ +<#else>
+ +
diff --git a/webapp/WEB-INF/templates/admin/search/solr_search_indexation_logs.html b/webapp/WEB-INF/templates/admin/search/solr_search_indexation_logs.html index 6655c51..3893e15 100644 --- a/webapp/WEB-INF/templates/admin/search/solr_search_indexation_logs.html +++ b/webapp/WEB-INF/templates/admin/search/solr_search_indexation_logs.html @@ -1,12 +1,41 @@
-

#i18n{portal.search.indexer_logs.titleIndexerLogs}

+
+<#if command?has_content> +

+ <#if running?? && running> +   #i18n{search.solr.adminFeature.operationInProgress} : + + <#else> + #i18n{search.solr.adminFeature.operationDone} : + + <#if command = "del"> + #i18n{search.solr.adminFeature.buttonDoDel} + <#elseif command = "total"> + #i18n{portal.search.manage_indexer.buttonDoIndex} + <#elseif command = "incremental" > + #i18n{portal.search.manage_indexer.buttonDoIncrementalIndex} + <#else> + ${command} + ... +

     ${logs}
-    
- -
- -
-
\ No newline at end of file + + +
+
diff --git a/webapp/WEB-INF/templates/skin/search/solr_search_results.html b/webapp/WEB-INF/templates/skin/search/solr_search_results.html index f1c3cdf..ba4ed01 100644 --- a/webapp/WEB-INF/templates/skin/search/solr_search_results.html +++ b/webapp/WEB-INF/templates/skin/search/solr_search_results.html @@ -1,5 +1,11 @@ <#setting url_escaping_charset=encoding> +<#if conf_user_query??> +<#assign conf_query = "&conf=${conf_user_query}"> +<#else> +<#assign conf_query = ""> + + <#-- Encode facet queries --> <#macro EncodeFQ list_fq> <#assign encoded_facets_queries = ""> @@ -8,6 +14,181 @@ ${encoded_facets_queries} +<#if conf.extraMappingQuery> + + + + + + + +
<#-- facets -->
@@ -21,13 +202,13 @@ <#list historique as fh> - ${fh.name} + ${fh.name} - #i18n{search.solr.display.result.raffinement.clear} + #i18n{search.solr.display.result.raffinement.clear} @@ -49,7 +230,7 @@ @@ -78,7 +259,7 @@ <#assign toDate = "${count.name}"?datetime("yyyy-MM-dd'T'HH:mm:ss'Z'")> <#assign daterange = "${field.name}:[${count.name} TO ${count.name}${facetDateGap}]"?url> <#assign toString = "${toDate?string('yyyy')}"> - ${toString}(${count.count}) + ${toString}(${count.count}) @@ -106,7 +287,7 @@ <#-- when there is no result, facet is not null, but facet.values is --> - ${facet.name} + ${facet.name} @@ -114,7 +295,7 @@ @@ -138,12 +319,12 @@ <#if field.enableSort> - ${field.label} desc + ${field.label} desc - ${field.label} asc + ${field.label} asc @@ -161,6 +342,9 @@
+ <#if conf_user_query??> + + <#if facets_list??> @@ -177,6 +361,9 @@
+ <#if conf.extraMappingQuery> +
+
<#-- Number of documents per page selector --> #i18n{portal.search.search_results.labelNbDocsPerPage}: @@ -193,17 +380,13 @@ <#-- spellChecker --> - <#if suggestion?has_content> + <#if suggestion?has_content>
- #i18n{search.solr.display.result.spellchecker} - <#list suggestion as sugg> - <#assign newQuery="" > - ${sugg.getCollationQueryString()} - + <#assign newQuery="" > + #i18n{search.solr.display.result.spellchecker}${suggestion?trim}
-