Added: ofbiz/trunk/specialpurpose/solr/solrdefault/conf/xslt/example_atom.xsl
URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/solr/solrdefault/conf/xslt/example_atom.xsl?rev=1700119&view=auto ============================================================================== --- ofbiz/trunk/specialpurpose/solr/solrdefault/conf/xslt/example_atom.xsl (added) +++ ofbiz/trunk/specialpurpose/solr/solrdefault/conf/xslt/example_atom.xsl Sun Aug 30 13:27:07 2015 @@ -0,0 +1,67 @@ +<?xml version='1.0' encoding='UTF-8'?> + +<!-- + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + --> + +<!-- + Simple transform of Solr query results to Atom + --> + +<xsl:stylesheet version='1.0' + xmlns:xsl='http://www.w3.org/1999/XSL/Transform'> + + <xsl:output + method="xml" + encoding="utf-8" + media-type="application/xml" + /> + + <xsl:template match='/'> + <xsl:variable name="query" select="response/lst[@name='responseHeader']/lst[@name='params']/str[@name='q']"/> + <feed xmlns="http://www.w3.org/2005/Atom"> + <title>Example Solr Atom 1.0 Feed</title> + <subtitle> + This has been formatted by the sample "example_atom.xsl" transform - + use your own XSLT to get a nicer Atom feed. + </subtitle> + <author> + <name>Apache Solr</name> + <email>[hidden email]</email> + </author> + <link rel="self" type="application/atom+xml" + href="http://localhost:8983/solr/q={$query}&wt=xslt&tr=atom.xsl"/> + <updated> + <xsl:value-of select="response/result/doc[position()=1]/date[@name='timestamp']"/> + </updated> + <id>tag:localhost,2007:example</id> + <xsl:apply-templates select="response/result/doc"/> + </feed> + </xsl:template> + + <!-- search results xslt --> + <xsl:template match="doc"> + <xsl:variable name="id" select="str[@name='id']"/> + <entry> + <title><xsl:value-of select="str[@name='name']"/></title> + <link href="http://localhost:8983/solr/select?q={$id}"/> + <id>tag:localhost,2007:<xsl:value-of select="$id"/></id> + <summary><xsl:value-of select="arr[@name='features']"/></summary> + <updated><xsl:value-of select="date[@name='timestamp']"/></updated> + </entry> + </xsl:template> + +</xsl:stylesheet> Propchange: ofbiz/trunk/specialpurpose/solr/solrdefault/conf/xslt/example_atom.xsl ------------------------------------------------------------------------------ svn:eol-style = native Propchange: ofbiz/trunk/specialpurpose/solr/solrdefault/conf/xslt/example_atom.xsl ------------------------------------------------------------------------------ svn:keywords = Date Rev Author URL Id Propchange: ofbiz/trunk/specialpurpose/solr/solrdefault/conf/xslt/example_atom.xsl ------------------------------------------------------------------------------ svn:mime-type = text/xsl Added: ofbiz/trunk/specialpurpose/solr/solrdefault/conf/xslt/example_rss.xsl URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/solr/solrdefault/conf/xslt/example_rss.xsl?rev=1700119&view=auto ============================================================================== --- ofbiz/trunk/specialpurpose/solr/solrdefault/conf/xslt/example_rss.xsl (added) +++ ofbiz/trunk/specialpurpose/solr/solrdefault/conf/xslt/example_rss.xsl Sun Aug 30 13:27:07 2015 @@ -0,0 +1,66 @@ +<?xml version='1.0' encoding='UTF-8'?> + +<!-- + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + --> + +<!-- + Simple transform of Solr query results to RSS + --> + +<xsl:stylesheet version='1.0' + xmlns:xsl='http://www.w3.org/1999/XSL/Transform'> + + <xsl:output + method="xml" + encoding="utf-8" + media-type="application/xml" + /> + <xsl:template match='/'> + <rss version="2.0"> + <channel> + <title>Example Solr RSS 2.0 Feed</title> + <link>http://localhost:8983/solr</link> + <description> + This has been formatted by the sample "example_rss.xsl" transform - + use your own XSLT to get a nicer RSS feed. + </description> + <language>en-us</language> + <docs>http://localhost:8983/solr</docs> + <xsl:apply-templates select="response/result/doc"/> + </channel> + </rss> + </xsl:template> + + <!-- search results xslt --> + <xsl:template match="doc"> + <xsl:variable name="id" select="str[@name='id']"/> + <xsl:variable name="timestamp" select="date[@name='timestamp']"/> + <item> + <title><xsl:value-of select="str[@name='name']"/></title> + <link> + http://localhost:8983/solr/select?q=id:<xsl:value-of select="$id"/> + </link> + <description> + <xsl:value-of select="arr[@name='features']"/> + </description> + <pubDate><xsl:value-of select="$timestamp"/></pubDate> + <guid> + http://localhost:8983/solr/select?q=id:<xsl:value-of select="$id"/> + </guid> + </item> + </xsl:template> +</xsl:stylesheet> Propchange: ofbiz/trunk/specialpurpose/solr/solrdefault/conf/xslt/example_rss.xsl ------------------------------------------------------------------------------ svn:eol-style = native Propchange: ofbiz/trunk/specialpurpose/solr/solrdefault/conf/xslt/example_rss.xsl ------------------------------------------------------------------------------ svn:keywords = Date Rev Author URL Id Propchange: ofbiz/trunk/specialpurpose/solr/solrdefault/conf/xslt/example_rss.xsl ------------------------------------------------------------------------------ svn:mime-type = text/xsl Added: ofbiz/trunk/specialpurpose/solr/solrdefault/conf/xslt/luke.xsl URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/solr/solrdefault/conf/xslt/luke.xsl?rev=1700119&view=auto ============================================================================== --- ofbiz/trunk/specialpurpose/solr/solrdefault/conf/xslt/luke.xsl (added) +++ ofbiz/trunk/specialpurpose/solr/solrdefault/conf/xslt/luke.xsl Sun Aug 30 13:27:07 2015 @@ -0,0 +1,337 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + + +<!-- + Display the luke request handler with graphs + --> +<xsl:stylesheet + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns="http://www.w3.org/1999/xhtml" + version="1.0" + > + <xsl:output + method="html" + encoding="UTF-8" + media-type="text/html" + doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" + doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" + /> + + <xsl:variable name="title">Solr Luke Request Handler Response</xsl:variable> + + <xsl:template match="/"> + <html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <link rel="stylesheet" type="text/css" href="solr-admin.css"/> + <link rel="icon" href="favicon.ico" type="image/ico"/> + <link rel="shortcut icon" href="favicon.ico" type="image/ico"/> + <title> + <xsl:value-of select="$title"/> + </title> + <xsl:call-template name="css"/> + + </head> + <body> + <h1> + <xsl:value-of select="$title"/> + </h1> + <div class="doc"> + <ul> + <xsl:if test="response/lst[@name='index']"> + <li> + <a href="#index">Index Statistics</a> + </li> + </xsl:if> + <xsl:if test="response/lst[@name='fields']"> + <li> + <a href="#fields">Field Statistics</a> + <ul> + <xsl:for-each select="response/lst[@name='fields']/lst"> + <li> + <a href="#{@name}"> + <xsl:value-of select="@name"/> + </a> + </li> + </xsl:for-each> + </ul> + </li> + </xsl:if> + <xsl:if test="response/lst[@name='doc']"> + <li> + <a href="#doc">Document statistics</a> + </li> + </xsl:if> + </ul> + </div> + <xsl:if test="response/lst[@name='index']"> + <h2><a name="index"/>Index Statistics</h2> + <xsl:apply-templates select="response/lst[@name='index']"/> + </xsl:if> + <xsl:if test="response/lst[@name='fields']"> + <h2><a name="fields"/>Field Statistics</h2> + <xsl:apply-templates select="response/lst[@name='fields']"/> + </xsl:if> + <xsl:if test="response/lst[@name='doc']"> + <h2><a name="doc"/>Document statistics</h2> + <xsl:apply-templates select="response/lst[@name='doc']"/> + </xsl:if> + </body> + </html> + </xsl:template> + + <xsl:template match="lst"> + <xsl:if test="parent::lst"> + <tr> + <td colspan="2"> + <div class="doc"> + <xsl:call-template name="list"/> + </div> + </td> + </tr> + </xsl:if> + <xsl:if test="not(parent::lst)"> + <div class="doc"> + <xsl:call-template name="list"/> + </div> + </xsl:if> + </xsl:template> + + <xsl:template name="list"> + <xsl:if test="count(child::*)>0"> + <table> + <thead> + <tr> + <th colspan="2"> + <p> + <a name="{@name}"/> + </p> + <xsl:value-of select="@name"/> + </th> + </tr> + </thead> + <tbody> + <xsl:choose> + <xsl:when + test="@name='histogram'"> + <tr> + <td colspan="2"> + <xsl:call-template name="histogram"/> + </td> + </tr> + </xsl:when> + <xsl:otherwise> + <xsl:apply-templates/> + </xsl:otherwise> + </xsl:choose> + </tbody> + </table> + </xsl:if> + </xsl:template> + + <xsl:template name="histogram"> + <div class="doc"> + <xsl:call-template name="barchart"> + <xsl:with-param name="max_bar_width">50</xsl:with-param> + <xsl:with-param name="iwidth">800</xsl:with-param> + <xsl:with-param name="iheight">160</xsl:with-param> + <xsl:with-param name="fill">blue</xsl:with-param> + </xsl:call-template> + </div> + </xsl:template> + + <xsl:template name="barchart"> + <xsl:param name="max_bar_width"/> + <xsl:param name="iwidth"/> + <xsl:param name="iheight"/> + <xsl:param name="fill"/> + <xsl:variable name="max"> + <xsl:for-each select="int"> + <xsl:sort data-type="number" order="descending"/> + <xsl:if test="position()=1"> + <xsl:value-of select="."/> + </xsl:if> + </xsl:for-each> + </xsl:variable> + <xsl:variable name="bars"> + <xsl:value-of select="count(int)"/> + </xsl:variable> + <xsl:variable name="bar_width"> + <xsl:choose> + <xsl:when test="$max_bar_width < ($iwidth div $bars)"> + <xsl:value-of select="$max_bar_width"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$iwidth div $bars"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <table class="histogram"> + <tbody> + <tr> + <xsl:for-each select="int"> + <td> + <xsl:value-of select="."/> + <div class="histogram"> + <xsl:attribute name="style">background-color: <xsl:value-of select="$fill"/>; width: <xsl:value-of select="$bar_width"/>px; height: <xsl:value-of select="($iheight*number(.)) div $max"/>px;</xsl:attribute> + </div> + </td> + </xsl:for-each> + </tr> + <tr> + <xsl:for-each select="int"> + <td> + <xsl:value-of select="@name"/> + </td> + </xsl:for-each> + </tr> + </tbody> + </table> + </xsl:template> + + <xsl:template name="keyvalue"> + <xsl:choose> + <xsl:when test="@name"> + <tr> + <td class="name"> + <xsl:value-of select="@name"/> + </td> + <td class="value"> + <xsl:value-of select="."/> + </td> + </tr> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="."/> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <xsl:template match="int|bool|long|float|double|uuid|date"> + <xsl:call-template name="keyvalue"/> + </xsl:template> + + <xsl:template match="arr"> + <tr> + <td class="name"> + <xsl:value-of select="@name"/> + </td> + <td class="value"> + <ul> + <xsl:for-each select="child::*"> + <li> + <xsl:apply-templates/> + </li> + </xsl:for-each> + </ul> + </td> + </tr> + </xsl:template> + + <xsl:template match="str"> + <xsl:choose> + <xsl:when test="@name='schema' or @name='index' or @name='flags'"> + <xsl:call-template name="schema"/> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="keyvalue"/> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <xsl:template name="schema"> + <tr> + <td class="name"> + <xsl:value-of select="@name"/> + </td> + <td class="value"> + <xsl:if test="contains(.,'unstored')"> + <xsl:value-of select="."/> + </xsl:if> + <xsl:if test="not(contains(.,'unstored'))"> + <xsl:call-template name="infochar2string"> + <xsl:with-param name="charList"> + <xsl:value-of select="."/> + </xsl:with-param> + </xsl:call-template> + </xsl:if> + </td> + </tr> + </xsl:template> + + <xsl:template name="infochar2string"> + <xsl:param name="i">1</xsl:param> + <xsl:param name="charList"/> + + <xsl:variable name="char"> + <xsl:value-of select="substring($charList,$i,1)"/> + </xsl:variable> + <xsl:choose> + <xsl:when test="$char='I'"> + <xsl:value-of select="/response/lst[@name='info']/lst/str[@name='I']"/> - </xsl:when> + <xsl:when test="$char='T'"> + <xsl:value-of select="/response/lst[@name='info']/lst/str[@name='T']"/> - </xsl:when> + <xsl:when test="$char='S'"> + <xsl:value-of select="/response/lst[@name='info']/lst/str[@name='S']"/> - </xsl:when> + <xsl:when test="$char='M'"> + <xsl:value-of select="/response/lst[@name='info']/lst/str[@name='M']"/> - </xsl:when> + <xsl:when test="$char='V'"> + <xsl:value-of select="/response/lst[@name='info']/lst/str[@name='V']"/> - </xsl:when> + <xsl:when test="$char='o'"> + <xsl:value-of select="/response/lst[@name='info']/lst/str[@name='o']"/> - </xsl:when> + <xsl:when test="$char='p'"> + <xsl:value-of select="/response/lst[@name='info']/lst/str[@name='p']"/> - </xsl:when> + <xsl:when test="$char='O'"> + <xsl:value-of select="/response/lst[@name='info']/lst/str[@name='O']"/> - </xsl:when> + <xsl:when test="$char='L'"> + <xsl:value-of select="/response/lst[@name='info']/lst/str[@name='L']"/> - </xsl:when> + <xsl:when test="$char='B'"> + <xsl:value-of select="/response/lst[@name='info']/lst/str[@name='B']"/> - </xsl:when> + <xsl:when test="$char='C'"> + <xsl:value-of select="/response/lst[@name='info']/lst/str[@name='C']"/> - </xsl:when> + <xsl:when test="$char='f'"> + <xsl:value-of select="/response/lst[@name='info']/lst/str[@name='f']"/> - </xsl:when> + <xsl:when test="$char='l'"> + <xsl:value-of select="/response/lst[@name='info']/lst/str[@name='l']"/> - + </xsl:when> + </xsl:choose> + + <xsl:if test="not($i>=string-length($charList))"> + <xsl:call-template name="infochar2string"> + <xsl:with-param name="i"> + <xsl:value-of select="$i+1"/> + </xsl:with-param> + <xsl:with-param name="charList"> + <xsl:value-of select="$charList"/> + </xsl:with-param> + </xsl:call-template> + </xsl:if> + </xsl:template> + <xsl:template name="css"> + <style type="text/css"> + <![CDATA[ + td.name {font-style: italic; font-size:80%; } + .doc { margin: 0.5em; border: solid grey 1px; } + .exp { display: none; font-family: monospace; white-space: pre; } + div.histogram { background: none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;} + table.histogram { width: auto; vertical-align: bottom; } + table.histogram td, table.histogram th { text-align: center; vertical-align: bottom; border-bottom: 1px solid #ff9933; width: auto; } + ]]> + </style> + </xsl:template> +</xsl:stylesheet> Propchange: ofbiz/trunk/specialpurpose/solr/solrdefault/conf/xslt/luke.xsl ------------------------------------------------------------------------------ svn:eol-style = native Propchange: ofbiz/trunk/specialpurpose/solr/solrdefault/conf/xslt/luke.xsl ------------------------------------------------------------------------------ svn:keywords = Date Rev Author URL Id Propchange: ofbiz/trunk/specialpurpose/solr/solrdefault/conf/xslt/luke.xsl ------------------------------------------------------------------------------ svn:mime-type = text/xsl Added: ofbiz/trunk/specialpurpose/solr/solrdefault/conf/xslt/updateXml.xsl URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/solr/solrdefault/conf/xslt/updateXml.xsl?rev=1700119&view=auto ============================================================================== --- ofbiz/trunk/specialpurpose/solr/solrdefault/conf/xslt/updateXml.xsl (added) +++ ofbiz/trunk/specialpurpose/solr/solrdefault/conf/xslt/updateXml.xsl Sun Aug 30 13:27:07 2015 @@ -0,0 +1,70 @@ +<!-- + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + --> + +<!-- + Simple transform of Solr query response into Solr Update XML compliant XML. + When used in the xslt response writer you will get UpdaateXML as output. + But you can also store a query response XML to disk and feed this XML to + the XSLTUpdateRequestHandler to index the content. Provided as example only. + See http://wiki.apache.org/solr/XsltUpdateRequestHandler for more info + --> +<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'> + <xsl:output media-type="text/xml" method="xml" indent="yes"/> + + <xsl:template match='/'> + <add> + <xsl:apply-templates select="response/result/doc"/> + </add> + </xsl:template> + + <!-- Ignore score (makes no sense to index) --> + <xsl:template match="doc/*[@name='score']" priority="100"> + </xsl:template> + + <xsl:template match="doc"> + <xsl:variable name="pos" select="position()"/> + <doc> + <xsl:apply-templates> + <xsl:with-param name="pos"><xsl:value-of select="$pos"/></xsl:with-param> + </xsl:apply-templates> + </doc> + </xsl:template> + + <!-- Flatten arrays to duplicate field lines --> + <xsl:template match="doc/arr" priority="100"> + <xsl:variable name="fn" select="@name"/> + + <xsl:for-each select="*"> + <xsl:element name="field"> + <xsl:attribute name="name"><xsl:value-of select="$fn"/></xsl:attribute> + <xsl:value-of select="."/> + </xsl:element> + </xsl:for-each> + </xsl:template> + + + <xsl:template match="doc/*"> + <xsl:variable name="fn" select="@name"/> + + <xsl:element name="field"> + <xsl:attribute name="name"><xsl:value-of select="$fn"/></xsl:attribute> + <xsl:value-of select="."/> + </xsl:element> + </xsl:template> + + <xsl:template match="*"/> +</xsl:stylesheet> Propchange: ofbiz/trunk/specialpurpose/solr/solrdefault/conf/xslt/updateXml.xsl ------------------------------------------------------------------------------ svn:eol-style = native Propchange: ofbiz/trunk/specialpurpose/solr/solrdefault/conf/xslt/updateXml.xsl ------------------------------------------------------------------------------ svn:keywords = Date Rev Author URL Id Propchange: ofbiz/trunk/specialpurpose/solr/solrdefault/conf/xslt/updateXml.xsl ------------------------------------------------------------------------------ svn:mime-type = text/xsl Added: ofbiz/trunk/specialpurpose/solr/solrdefault/core.properties URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/solr/solrdefault/core.properties?rev=1700119&view=auto ============================================================================== --- ofbiz/trunk/specialpurpose/solr/solrdefault/core.properties (added) +++ ofbiz/trunk/specialpurpose/solr/solrdefault/core.properties Sun Aug 30 13:27:07 2015 @@ -0,0 +1,2 @@ +# To config this file, please read: +# https://cwiki.apache.org/confluence/display/solr/Defining+core.properties Propchange: ofbiz/trunk/specialpurpose/solr/solrdefault/core.properties ------------------------------------------------------------------------------ svn:eol-style = native Propchange: ofbiz/trunk/specialpurpose/solr/solrdefault/core.properties ------------------------------------------------------------------------------ svn:keywords = Date Rev Author URL Id Propchange: ofbiz/trunk/specialpurpose/solr/solrdefault/core.properties ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: ofbiz/trunk/specialpurpose/solr/src/org/ofbiz/solr/CategoryUtil.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/solr/src/org/ofbiz/solr/CategoryUtil.java?rev=1700119&view=auto ============================================================================== --- ofbiz/trunk/specialpurpose/solr/src/org/ofbiz/solr/CategoryUtil.java (added) +++ ofbiz/trunk/specialpurpose/solr/src/org/ofbiz/solr/CategoryUtil.java Sun Aug 30 13:27:07 2015 @@ -0,0 +1,189 @@ +/******************************************************************************* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + *******************************************************************************/ +package org.ofbiz.solr; + +import java.util.Iterator; +import java.util.List; + +import javolution.util.FastList; + +import org.apache.commons.lang.StringUtils; +import org.ofbiz.base.util.Debug; +import org.ofbiz.base.util.UtilMisc; +import org.ofbiz.base.util.UtilValidate; +import org.ofbiz.entity.Delegator; +import org.ofbiz.entity.GenericDelegator; +import org.ofbiz.entity.GenericEntityException; +import org.ofbiz.entity.GenericValue; +import org.ofbiz.entity.condition.EntityCondition; +import org.ofbiz.entity.util.EntityUtil; +import org.ofbiz.service.DispatchContext; + +/** + * Product category util class for solr. + */ +public abstract class CategoryUtil { + + public static final String module = CategoryUtil.class.getName(); + + /** + * Gets catalog IDs for specified product category. + * <p> + * This method is a supplement to CatalogWorker methods. + */ + public static List<String> getCatalogIdsByCategoryId(Delegator delegator, String productCategoryId) { + List<String> catalogIds = FastList.newInstance(); + List<GenericValue> catalogs = null; + try { + EntityCondition condition = EntityCondition.makeCondition(UtilMisc.toMap("productCategoryId", productCategoryId)); + // catalogs = delegator.findList("ProdCatalog", null, null, UtilMisc.toList("catalogName"), null, false); + catalogs = delegator.findList("ProdCatalogCategory", condition, null, null, null, false); + } catch (GenericEntityException e) { + Debug.logError(e, "Error looking up all catalogs", module); + } + if (catalogs != null) { + for (GenericValue c : catalogs) { + catalogIds.add(c.getString("prodCatalogId")); + } + } + return catalogIds; + } + + public static List<List<String>> getCategoryTrail(String productCategoryId, DispatchContext dctx) { + GenericDelegator delegator = (GenericDelegator) dctx.getDelegator(); + List<List<String>> trailElements = FastList.newInstance(); + String parentProductCategoryId = productCategoryId; + while (UtilValidate.isNotEmpty(parentProductCategoryId)) { + // find product category rollup + try { + List<EntityCondition> rolllupConds = FastList.newInstance(); + rolllupConds.add(EntityCondition.makeCondition("productCategoryId", parentProductCategoryId)); + rolllupConds.add(EntityUtil.getFilterByDateExpr()); + List<GenericValue> productCategoryRollups = delegator.findList("ProductCategoryRollup", EntityCondition.makeCondition(rolllupConds), null, UtilMisc.toList("-fromDate"), null, true); + if (UtilValidate.isNotEmpty(productCategoryRollups)) { + List<List<String>> trailElementsAux = FastList.newInstance(); + trailElementsAux.addAll(trailElements); + // add only categories that belong to the top category to trail + for (GenericValue productCategoryRollup : productCategoryRollups) { + String trailCategoryId = productCategoryRollup.getString("parentProductCategoryId"); + parentProductCategoryId = trailCategoryId; + List<String> trailElement = FastList.newInstance(); + if (!trailElements.isEmpty()) { + for (List<String> trailList : trailElementsAux) { + trailElement.add(trailCategoryId); + trailElement.addAll(trailList); + trailElements.remove(trailList); + trailElements.add(trailElement); + } + } else { + trailElement.add(trailCategoryId); + trailElement.add(productCategoryId); + trailElements.add(trailElement); + } + } + } else { + parentProductCategoryId = null; + } + + } catch (GenericEntityException e) { + Debug.logError(e, "Cannot generate trail from product category", module); + } + } + if (trailElements.size() == 0) { + List<String> trailElement = FastList.newInstance(); + trailElement.add(productCategoryId); + trailElements.add(trailElement); + } + return trailElements; + } + + /** + * Returns categoryName with trail + */ + public static String getCategoryNameWithTrail(String productCategoryId, DispatchContext dctx) { + return getCategoryNameWithTrail(productCategoryId, true, dctx); + } + + public static String getCategoryNameWithTrail(String productCategoryId, Boolean showDepth, DispatchContext dctx) { + List<List<String>> trailElements = CategoryUtil.getCategoryTrail(productCategoryId, dctx); + //Debug.log("trailElements ======> " + trailElements.toString()); + StringBuilder catMember = new StringBuilder(); + String cm =""; + int i = 0; + for (List<String> trailElement : trailElements) { + for (Iterator<String> trailIter = trailElement.iterator(); trailIter.hasNext();) { + String trailString = (String) trailIter.next(); + if (catMember.length() > 0){ + catMember.append("/"); + i++; + } + + catMember.append(trailString); + } + } + + if (catMember.length() == 0){catMember.append(productCategoryId);} + + if(showDepth) { + cm = i +"/"+ catMember.toString(); + } else { + cm = catMember.toString(); + } + //Debug.logInfo("catMember "+cm,module); + return cm; + } + + /** + * Returns nextLevel from trailed category. + * <p> + * Ie for "1/SYRACUS2_CATEGORY/FICTION_C/" the returned value would be 2. + */ + public static int getNextLevelFromCategoryId(String productCategoryId, DispatchContext dctx) { + try{ + if (productCategoryId.contains("/")) { + String[] productCategories = productCategoryId.split("/"); + int level = Integer.parseInt(productCategories[0]); + return level++; + } else { + return 0; + } + } catch(Exception e) { + return 0; + } + } + + /** + * Returns proper FacetFilter from trailed category. + * <p> + * Ie for "1/SYRACUS2_CATEGORY/FICTION_C/" the returned value would be + * "2/SYRACUS2_CATEGORY/FICTION_C/". + */ + public static String getFacetFilterForCategory(String productCategoryId, DispatchContext dctx) { + try{ + String[] productCategories = productCategoryId.split("/"); + int level = Integer.parseInt(productCategories[0]); + int nextLevel = level+1; + productCategories[0] = ""+nextLevel; + return StringUtils.join(productCategories,"/"); + } catch(Exception e) { + return productCategoryId; + } + } + +} \ No newline at end of file Propchange: ofbiz/trunk/specialpurpose/solr/src/org/ofbiz/solr/CategoryUtil.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: ofbiz/trunk/specialpurpose/solr/src/org/ofbiz/solr/CategoryUtil.java ------------------------------------------------------------------------------ svn:keywords = Date Rev Author URL Id Propchange: ofbiz/trunk/specialpurpose/solr/src/org/ofbiz/solr/CategoryUtil.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: ofbiz/trunk/specialpurpose/solr/src/org/ofbiz/solr/ProductUtil.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/solr/src/org/ofbiz/solr/ProductUtil.java?rev=1700119&view=auto ============================================================================== --- ofbiz/trunk/specialpurpose/solr/src/org/ofbiz/solr/ProductUtil.java (added) +++ ofbiz/trunk/specialpurpose/solr/src/org/ofbiz/solr/ProductUtil.java Sun Aug 30 13:27:07 2015 @@ -0,0 +1,232 @@ +/******************************************************************************* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + *******************************************************************************/ +package org.ofbiz.solr; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +import javolution.util.FastList; +import javolution.util.FastMap; + +import org.ofbiz.base.util.Debug; +import org.ofbiz.base.util.UtilMisc; +import org.ofbiz.entity.GenericDelegator; +import org.ofbiz.entity.GenericEntityException; +import org.ofbiz.entity.GenericValue; +import org.ofbiz.entity.condition.EntityCondition; +import org.ofbiz.product.config.ProductConfigWrapper; +import org.ofbiz.product.product.ProductContentWrapper; +import org.ofbiz.product.product.ProductWorker; +import org.ofbiz.service.DispatchContext; +import org.ofbiz.service.LocalDispatcher; + +/** + * Product utility class for solr. + */ +public abstract class ProductUtil { + public static final String module = ProductUtil.class.getName(); + + public static Map<String, Object> getProductContent(GenericValue product, DispatchContext dctx, Map<String, Object> context) { + GenericDelegator delegator = (GenericDelegator) dctx.getDelegator(); + LocalDispatcher dispatcher = dctx.getDispatcher(); + GenericValue userLogin = (GenericValue) context.get("userLogin"); + String productId = (String) product.get("productId"); + Map<String, Object> dispatchContext = new HashMap<String, Object>(); + Locale locale = new Locale("de_DE"); + + if (Debug.verboseOn()) { + Debug.logVerbose("Solr: Getting product content for productId '" + productId + "'", module); + } + + try { + // Generate special ProductContentWrapper for the supported languages (de/en/fr) + ProductContentWrapper productContentEn = new ProductContentWrapper(dispatcher, product, new Locale("en"), null); + ProductContentWrapper productContentDe = new ProductContentWrapper(dispatcher, product, new Locale("de"), null); + ProductContentWrapper productContentFr = new ProductContentWrapper(dispatcher, product, new Locale("fr"), null); + if (productId != null) { + dispatchContext.put("productId", productId); + // if (product.get("sku") != null) dispatchContext.put("sku", product.get("sku")); + if (product.get("internalName") != null) + dispatchContext.put("internalName", product.get("internalName")); + // GenericValue manu = product.getRelatedOneCache("Manufacturer"); + // if (product.get("manu") != null) dispatchContext.put("manu", ""); + String smallImage = (String) product.get("smallImageUrl"); + if (smallImage != null) + dispatchContext.put("smallImage", smallImage); + String mediumImage = (String) product.get("mediumImageUrl"); + if (mediumImage != null) + dispatchContext.put("mediumImage", mediumImage); + String largeImage = (String) product.get("largeImageUrl"); + if (largeImage != null) + dispatchContext.put("largeImage", largeImage); + + // if(product.get("weight") != null) dispatchContext.put("weight", ""); + + // Trying to set a correctand trail + List<GenericValue> category = delegator.findList("ProductCategoryMember", EntityCondition.makeCondition(UtilMisc.toMap("productId", productId)), null, null, null, false); + List<String> trails = new ArrayList<String>(); + for (Iterator<GenericValue> catIterator = category.iterator(); catIterator.hasNext();) { + GenericValue cat = (GenericValue) catIterator.next(); + String productCategoryId = (String) cat.get("productCategoryId"); + List<List<String>> trailElements = CategoryUtil.getCategoryTrail(productCategoryId, dctx); + //Debug.log("trailElements ======> " + trailElements.toString()); + for (List<String> trailElement : trailElements) { + StringBuilder catMember = new StringBuilder(); + int i = 0; + Iterator<String> trailIter = trailElement.iterator(); + + while (trailIter.hasNext()) { + String trailString = (String) trailIter.next(); + if (catMember.length() > 0){ + catMember.append("/"); + i++; + } + catMember.append(trailString); + String cm = i +"/"+ catMember.toString(); + if (!trails.contains(cm)) { + //Debug.logInfo("cm : "+cm, module); + trails.add(cm); + // Debug.log("trail for product " + productId + " ====> " + catMember.toString()); + } + } + + } + } + dispatchContext.put("category", trails); + + // Get the catalogs that have associated the categories + List<String> catalogs = FastList.newInstance(); + for (String trail : trails) { + String productCategoryId = (trail.split("/").length > 0) ? trail.split("/")[1] : trail; + List<String> catalogMembers = CategoryUtil.getCatalogIdsByCategoryId(delegator, productCategoryId); + for (String catalogMember : catalogMembers) + if (!catalogs.contains(catalogMember)) + catalogs.add(catalogMember); + } + dispatchContext.put("catalog", catalogs); + + // Alternative + // if(category.size()>0) dispatchContext.put("category", category); + // if(product.get("popularity") != null) dispatchContext.put("popularity", ""); + + Map<String, Object> featureSet = dispatcher.runSync("getProductFeatureSet", UtilMisc.toMap("productId", productId)); + if (featureSet != null) { + dispatchContext.put("features", (Set<?>) featureSet.get("featureSet")); + } + + Map<String, Object> productInventoryAvailable = dispatcher.runSync("getProductInventoryAvailable", UtilMisc.toMap("productId", productId)); + String inStock = null; + BigDecimal availableToPromiseTotal = (BigDecimal) productInventoryAvailable.get("availableToPromiseTotal"); + if (availableToPromiseTotal != null) { + inStock = availableToPromiseTotal.toBigInteger().toString(); + } + dispatchContext.put("inStock", inStock); + + Boolean isVirtual = ProductWorker.isVirtual(delegator, productId); + if (isVirtual) + dispatchContext.put("isVirtual", isVirtual); + Boolean isDigital = ProductWorker.isDigital(product); + if (isDigital) + dispatchContext.put("isDigital", isDigital); + Boolean isPhysical = ProductWorker.isPhysical(product); + if (isPhysical) + dispatchContext.put("isPhysical", isPhysical); + + FastMap<String, String> title = new FastMap<String, String>(); + String detitle = productContentDe.get("PRODUCT_NAME").toString(); + if (detitle != null) + title.put("de", detitle); + else if (product.get("productName") != null) + title.put("de", (String) product.get("productName")); + String entitle = productContentEn.get("PRODUCT_NAME").toString(); + if (entitle != null) + title.put("en", entitle); + else if (product.get("productName") != null) + title.put("en", (String) product.get("productName")); + String frtitle = productContentFr.get("PRODUCT_NAME").toString(); + if (frtitle != null) + title.put("fr", frtitle); + else if (product.get("productName") != null) + title.put("fr", (String) product.get("productName")); + dispatchContext.put("title", title); + + Map<String, String> description = new FastMap<String, String>(); + String dedescription = productContentDe.get("DESCRIPTION").toString(); + if (dedescription != null) + description.put("de", dedescription); + String endescription = productContentEn.get("DESCRIPTION").toString(); + if (endescription != null) + description.put("en", endescription); + String frdescription = productContentFr.get("DESCRIPTION").toString(); + if (frdescription != null) + description.put("fr", frdescription); + dispatchContext.put("description", description); + + FastMap<String, String> longDescription = new FastMap<String, String>(); + String delongDescription = productContentDe.get("LONG_DESCRIPTION").toString(); + if (delongDescription != null) + longDescription.put("de", delongDescription); + String enlongDescription = productContentEn.get("LONG_DESCRIPTION").toString(); + if (enlongDescription != null) + longDescription.put("en", enlongDescription); + String frlongDescription = productContentFr.get("LONG_DESCRIPTION").toString(); + if (frlongDescription != null) + longDescription.put("fr", frlongDescription); + dispatchContext.put("longDescription", longDescription); + + // dispatchContext.put("comments", ""); + // dispatchContext.put("keywords", ""); + // dispatchContext.put("last_modified", ""); + + if (product != null && "AGGREGATED".equals(product.getString("productTypeId"))) { + ProductConfigWrapper configWrapper = new ProductConfigWrapper(delegator, dispatcher, productId, null, null, null, null, locale, userLogin); + String listPrice = configWrapper.getTotalListPrice().setScale(2, BigDecimal.ROUND_HALF_DOWN).toString(); + if (listPrice != null) + dispatchContext.put("listPrice", listPrice); + String defaultPrice = configWrapper.getTotalListPrice().setScale(2, BigDecimal.ROUND_HALF_DOWN).toString(); + if (defaultPrice != null) + dispatchContext.put("defaultPrice", defaultPrice); + } else { + Map<String, GenericValue> priceContext = UtilMisc.toMap("product", product); + Map<String, Object> priceMap = dispatcher.runSync("calculateProductPrice", priceContext); + if (priceMap.get("listPrice") != null) { + String listPrice = ((BigDecimal) priceMap.get("listPrice")).setScale(2, BigDecimal.ROUND_HALF_DOWN).toString(); + dispatchContext.put("listPrice", listPrice); + } + if (priceMap.get("defaultPrice") != null) { + String defaultPrice = ((BigDecimal) priceMap.get("defaultPrice")).setScale(2, BigDecimal.ROUND_HALF_DOWN).toString(); + if (defaultPrice != null) + dispatchContext.put("defaultPrice", defaultPrice); + } + } + } + } catch (GenericEntityException e) { + Debug.logError(e, e.getMessage(), module); + } catch (Exception e) { + Debug.logError(e, e.getMessage(), module); + } + return dispatchContext; + } +} \ No newline at end of file Propchange: ofbiz/trunk/specialpurpose/solr/src/org/ofbiz/solr/ProductUtil.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: ofbiz/trunk/specialpurpose/solr/src/org/ofbiz/solr/ProductUtil.java ------------------------------------------------------------------------------ svn:keywords = Date Rev Author URL Id Propchange: ofbiz/trunk/specialpurpose/solr/src/org/ofbiz/solr/ProductUtil.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: ofbiz/trunk/specialpurpose/solr/src/org/ofbiz/solr/SolrProductSearch.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/solr/src/org/ofbiz/solr/SolrProductSearch.java?rev=1700119&view=auto ============================================================================== --- ofbiz/trunk/specialpurpose/solr/src/org/ofbiz/solr/SolrProductSearch.java (added) +++ ofbiz/trunk/specialpurpose/solr/src/org/ofbiz/solr/SolrProductSearch.java Sun Aug 30 13:27:07 2015 @@ -0,0 +1,675 @@ +/******************************************************************************* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + *******************************************************************************/ +package org.ofbiz.solr; + +import java.io.IOException; +import java.net.ConnectException; +import java.net.MalformedURLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import javolution.util.FastList; +import javolution.util.FastMap; + +import org.apache.commons.lang.StringUtils; +import org.apache.solr.client.solrj.SolrQuery; +import org.apache.solr.client.solrj.SolrServerException; +import org.apache.solr.client.solrj.impl.HttpSolrServer; +import org.apache.solr.client.solrj.response.FacetField; +import org.apache.solr.client.solrj.response.FacetField.Count; +import org.apache.solr.client.solrj.response.QueryResponse; +import org.apache.solr.client.solrj.response.SpellCheckResponse.Suggestion; +import org.apache.solr.common.SolrInputDocument; +import org.ofbiz.base.util.Debug; +import org.ofbiz.base.util.UtilGenerics; +import org.ofbiz.base.util.UtilMisc; +import org.ofbiz.base.util.UtilValidate; +import org.ofbiz.entity.Delegator; +import org.ofbiz.entity.GenericDelegator; +import org.ofbiz.entity.GenericEntityException; +import org.ofbiz.entity.GenericValue; +import org.ofbiz.service.DispatchContext; +import org.ofbiz.service.GenericServiceException; +import org.ofbiz.service.LocalDispatcher; +import org.ofbiz.service.ServiceAuthException; +import org.ofbiz.service.ServiceUtil; +import org.ofbiz.service.ServiceValidationException; + +/** + * Base class for OFBiz Test Tools test case implementations. + */ +public abstract class SolrProductSearch { + + public static final String module = SolrProductSearch.class.getName(); + + + /** + * Adds product to solr, with product denoted by productId field in instance attribute + * - intended for use with ECAs/SECAs. + */ + public static Map<String, Object> addToSolr(DispatchContext dctx, Map<String, Object> context) throws GenericEntityException { + Map<String, Object> result; + LocalDispatcher dispatcher = dctx.getDispatcher(); + Delegator delegator = dctx.getDelegator(); + GenericValue productInstance = (GenericValue) context.get("instance"); + String productId = (String) productInstance.get("productId"); + + if (SolrUtil.isSolrEcaEnabled()) { + // Debug.logVerbose("Solr: addToSolr: Running indexing for productId '" + productId + "'", module); + try { + GenericValue product = delegator.findOne("Product", UtilMisc.toMap("productId", productId), false); + Map<String, Object> dispatchContext = ProductUtil.getProductContent(product, dctx, context); + dispatchContext.put("treatConnectErrorNonFatal", SolrUtil.isEcaTreatConnectErrorNonFatal()); + Map<String, Object> runResult = dispatcher.runSync("addToSolrIndex", dispatchContext); + String runMsg = ServiceUtil.getErrorMessage(runResult); + if (UtilValidate.isEmpty(runMsg)) { + runMsg = null; + } + if (ServiceUtil.isError(runResult)) { + result = ServiceUtil.returnError(runMsg); + } + else if (ServiceUtil.isFailure(runResult)) { + result = ServiceUtil.returnFailure(runMsg); + } + else { + result = ServiceUtil.returnSuccess(); + } + } catch (Exception e) { + Debug.logError(e, e.getMessage(), module); + result = ServiceUtil.returnError(e.toString()); + } + } + else { + final String statusMsg = "Solr ECA indexing disabled; skipping indexing for productId '" + productId + "'"; + Debug.logVerbose("Solr: addToSolr: " + statusMsg, module); + result = ServiceUtil.returnSuccess(); + } + return result; + } + + /** + * Adds product to solr index. + */ + public static Map<String, Object> addToSolrIndex(DispatchContext dctx, Map<String, Object> context) throws GenericEntityException { + HttpSolrServer server = null; + Map<String, Object> result; + String productId = (String) context.get("productId"); + // connectErrorNonFatal is a necessary option because in some cases it may be considered normal that solr server is unavailable; + // don't want to return error and abort transactions in these cases. + Boolean treatConnectErrorNonFatal = (Boolean) context.get("treatConnectErrorNonFatal"); + try { + Debug.logInfo("Solr: Generating and indexing document for productId '" + productId + "'", module); + + server = new HttpSolrServer(SolrUtil.solrUrl); + //Debug.log(server.ping().toString()); + + // Construct Documents + SolrInputDocument doc1 = SolrUtil.generateSolrDocument(context); + Collection<SolrInputDocument> docs = new ArrayList<SolrInputDocument>(); + + if (Debug.verboseOn()) { + Debug.logVerbose("Solr: Indexing document: " + doc1.toString(), module); + } + + docs.add(doc1); + + // push Documents to server + server.add(docs); + server.commit(); + + final String statusStr = "Document for productId " + productId + " added to solr index"; + Debug.logInfo("Solr: " + statusStr, module); + result = ServiceUtil.returnSuccess(statusStr); + } catch (MalformedURLException e) { + Debug.logError(e, e.getMessage(), module); + result = ServiceUtil.returnError(e.toString()); + result.put("errorType", "urlError"); + } catch (SolrServerException e) { + if (e.getCause() != null && e.getCause() instanceof ConnectException) { + final String statusStr = "Failure connecting to solr server to commit productId " + + context.get("productId") + "; product not updated"; + if (Boolean.TRUE.equals(treatConnectErrorNonFatal)) { + Debug.logWarning(e, "Solr: " + statusStr, module); + result = ServiceUtil.returnFailure(statusStr); + } + else { + Debug.logError(e, "Solr: " + statusStr, module); + result = ServiceUtil.returnError(statusStr); + } + result.put("errorType", "connectError"); + } + else { + Debug.logError(e, e.getMessage(), module); + result = ServiceUtil.returnError(e.toString()); + result.put("errorType", "solrServerError"); + } + } catch (IOException e) { + Debug.logError(e, e.getMessage(), module); + result = ServiceUtil.returnError(e.toString()); + result.put("errorType", "ioError"); + } + return result; + } + + /** + * Adds a List of products to the solr index. + * <p> + * This is faster than reflushing the index each time. + */ + public static Map<String, Object> addListToSolrIndex(DispatchContext dctx, Map<String, Object> context) throws GenericEntityException { + HttpSolrServer server = null; + Map<String, Object> result; + Boolean treatConnectErrorNonFatal = (Boolean) context.get("treatConnectErrorNonFatal"); + try { + Collection<SolrInputDocument> docs = new ArrayList<SolrInputDocument>(); + + // Construct Documents + List<Map<String, Object>> fieldList = UtilGenerics.<Map<String, Object>>checkList(context.get("fieldList")); + + Debug.logInfo("Solr: Generating and adding " + fieldList.size() + " documents to solr index", module); + + for (Iterator<Map<String, Object>> fieldListIterator = fieldList.iterator(); fieldListIterator.hasNext();) { + SolrInputDocument doc1 = SolrUtil.generateSolrDocument(fieldListIterator.next()); + if (Debug.verboseOn()) { + Debug.logVerbose("Solr: Indexing document: " + doc1.toString(), module); + } + docs.add(doc1); + } + // push Documents to server + server = new HttpSolrServer(SolrUtil.solrUrl); + server.add(docs); + server.commit(); + + final String statusStr = "Added " + fieldList.size() + " documents to solr index"; + Debug.logInfo("Solr: " + statusStr, module); + result = ServiceUtil.returnSuccess(statusStr); + } catch (MalformedURLException e) { + Debug.logError(e, e.getMessage(), module); + result = ServiceUtil.returnError(e.toString()); + result.put("errorType", "urlError"); + } catch (SolrServerException e) { + if (e.getCause() != null && e.getCause() instanceof ConnectException) { + final String statusStr = "Failure connecting to solr server to commit product list; products not updated"; + if (Boolean.TRUE.equals(treatConnectErrorNonFatal)) { + Debug.logWarning(e, "Solr: " + statusStr, module); + result = ServiceUtil.returnFailure(statusStr); + } + else { + Debug.logError(e, "Solr: " + statusStr, module); + result = ServiceUtil.returnError(statusStr); + } + result.put("errorType", "connectError"); + } + else { + Debug.logError(e, e.getMessage(), module); + result = ServiceUtil.returnError(e.toString()); + result.put("errorType", "solrServerError"); + } + } catch (IOException e) { + Debug.logError(e, e.getMessage(), module); + result = ServiceUtil.returnError(e.toString()); + result.put("errorType", "ioError"); + } + return result; + } + + /** + * Runs a query on the Solr Search Engine and returns the results. + * <p> + * This function only returns an object of type QueryResponse, so it is probably not a good idea to call it directly from within the + * groovy files (As a decent example on how to use it, however, use keywordSearch instead). + */ + public static Map<String, Object> runSolrQuery(DispatchContext dctx, Map<String, Object> context) { + // get Connection + HttpSolrServer server = null; + Map<String, Object> result; + try { + server = new HttpSolrServer(SolrUtil.solrUrl); + // create Query Object + SolrQuery solrQuery = new SolrQuery(); + solrQuery.setQuery((String) context.get("query")); + // solrQuery.setQueryType("dismax"); + boolean faceted = (Boolean) context.get("facet"); + if (faceted) { + solrQuery.setFacet(faceted); + solrQuery.addFacetField("manu"); + solrQuery.addFacetField("cat"); + solrQuery.setFacetMinCount(1); + solrQuery.setFacetLimit(8); + + solrQuery.addFacetQuery("listPrice:[0 TO 50]"); + solrQuery.addFacetQuery("listPrice:[50 TO 100]"); + solrQuery.addFacetQuery("listPrice:[100 TO 250]"); + solrQuery.addFacetQuery("listPrice:[250 TO 500]"); + solrQuery.addFacetQuery("listPrice:[500 TO 1000]"); + solrQuery.addFacetQuery("listPrice:[1000 TO 2500]"); + solrQuery.addFacetQuery("listPrice:[2500 TO 5000]"); + solrQuery.addFacetQuery("listPrice:[5000 TO 10000]"); + solrQuery.addFacetQuery("listPrice:[10000 TO 50000]"); + solrQuery.addFacetQuery("listPrice:[50000 TO *]"); + } + + boolean spellCheck = (Boolean) context.get("spellcheck"); + if(spellCheck){ + solrQuery.setParam("spellcheck", spellCheck); + } + + boolean highLight = (Boolean) context.get("highlight"); + if (highLight) { + solrQuery.setHighlight(highLight); + solrQuery.setHighlightSimplePre("<span class=\"highlight\">"); + solrQuery.addHighlightField("description"); + solrQuery.setHighlightSimplePost("</span>"); + solrQuery.setHighlightSnippets(2); + } + + // Set additional Parameter + // SolrQuery.ORDER order = SolrQuery.ORDER.desc; + + if (context.get("viewIndex") != null && (Integer) context.get("viewIndex") > 0) { + solrQuery.setStart((Integer) context.get("viewIndex")); + } + if (context.get("viewSize") != null && (Integer) context.get("viewSize") > 0) { + solrQuery.setRows((Integer) context.get("viewSize")); + } + + // if ((List) context.get("queryFilter") != null && ((ArrayList<SolrDocument>) context.get("queryFilter")).size() > 0) { + // List filter = (List) context.get("queryFilter"); + // String[] tn = new String[filter.size()]; + // Iterator it = filter.iterator(); + // for (int i = 0; i < filter.size(); i++) { + // tn[i] = (String) filter.get(i); + // } + // solrQuery.setFilterQueries(tn); + // } + String queryFilter = (String) context.get("queryFilter"); + if(UtilValidate.isNotEmpty(queryFilter)) + solrQuery.setFilterQueries(queryFilter.split(" ")); + if ((String) context.get("returnFields") != null) { + solrQuery.setFields((String) context.get("returnFields")); + } + + // if((Boolean)context.get("sortByReverse"))order.reverse(); + if ((String) context.get("sortBy") != null && ((String) context.get("sortBy")).length() > 0) { + SolrQuery.ORDER order; + if (!((Boolean) context.get("sortByReverse"))) + order = SolrQuery.ORDER.asc; + else + order = SolrQuery.ORDER.desc; + solrQuery.setSort(((String) context.get("sortBy")).replaceFirst("-", ""), order); + } + + if ((String) context.get("facetQuery") != null) { + solrQuery.addFacetQuery((String) context.get("facetQuery")); + } + + QueryResponse rsp = server.query(solrQuery); + result = ServiceUtil.returnSuccess(); + result.put("queryResult", rsp); + } catch (Exception e) { + Debug.logError(e, e.getMessage(), module); + result = ServiceUtil.returnError(e.toString()); + } + return result; + } + + /** + * Performs solr products search. + */ + public static Map<String, Object> productsSearch(DispatchContext dctx, Map<String, Object> context) { + Map<String, Object> result; + LocalDispatcher dispatcher = dctx.getDispatcher(); + + try { + Map<String, Object> dispatchMap = FastMap.newInstance(); + if (UtilValidate.isNotEmpty(context.get("productCategoryId"))){ + String productCategoryId = (String) context.get("productCategoryId"); + dispatchMap.put("query", "cat:*" + productCategoryId+"*"); + } + else + return ServiceUtil.returnError("Missing product category id"); + if (context.get("viewSize") != null) + dispatchMap.put("viewSize", Integer.parseInt(((String) context.get("viewSize")))); + if (context.get("viewIndex") != null) + dispatchMap.put("viewIndex", Integer.parseInt((String) context.get("viewIndex"))); + if (context.get("queryFilter") != null) + dispatchMap.put("queryFilter", context.get("queryFilter")); + dispatchMap.put("facet", false); + dispatchMap.put("spellcheck", true); + dispatchMap.put("highlight", true); + Map<String, Object> searchResult = dispatcher.runSync("runSolrQuery", dispatchMap); + QueryResponse queryResult = (QueryResponse) searchResult.get("queryResult"); + result = ServiceUtil.returnSuccess(); + result.put("results", queryResult.getResults()); + result.put("listSize", queryResult.getResults().getNumFound()); + result.put("viewIndex", queryResult.getResults().getStart()); + result.put("viewSize", queryResult.getResults().size()); + } catch (Exception e) { + Debug.logError(e, e.getMessage(), module); + result = ServiceUtil.returnError(e.toString()); + } + return result; + } + + /** + * Performs keyword search. + * <p> + * The search form requires the result to be in a specific layout, so this will generate the proper results. + */ + public static Map<String, Object> keywordSearch(DispatchContext dctx, Map<String, Object> context) { + Map<String, Object> result; + LocalDispatcher dispatcher = dctx.getDispatcher(); + + try { + if (context.get("query") == null || context.get("query").equals("")) + context.put("query", "*:*"); + + Map<String, Object> dispatchMap = FastMap.newInstance(); + if (context.get("viewSize") != null) + dispatchMap.put("viewSize", Integer.parseInt(((String) context.get("viewSize")))); + if (context.get("viewIndex") != null) + dispatchMap.put("viewIndex", Integer.parseInt((String) context.get("viewIndex"))); + if (context.get("query") != null) + dispatchMap.put("query", context.get("query")); + if (context.get("queryFilter") != null) + dispatchMap.put("queryFilter", context.get("queryFilter")); + dispatchMap.put("spellcheck", true); + Map<String, Object> searchResult = dispatcher.runSync("runSolrQuery", dispatchMap); + QueryResponse queryResult = (QueryResponse) searchResult.get("queryResult"); + + List<List<String>> suggestions = FastList.newInstance(); + if (queryResult.getSpellCheckResponse() != null && queryResult.getSpellCheckResponse().getSuggestions() != null) { + Iterator<Suggestion> iter = queryResult.getSpellCheckResponse().getSuggestions().iterator(); + while (iter.hasNext()) { + Suggestion resultDoc = iter.next(); + Debug.logInfo("Suggestion " + resultDoc.getAlternatives(), module); + suggestions.add(resultDoc.getAlternatives()); + } + } + + Boolean isCorrectlySpelled = true; + if (queryResult.getSpellCheckResponse() != null) { + isCorrectlySpelled = queryResult.getSpellCheckResponse().isCorrectlySpelled(); + } + + result = ServiceUtil.returnSuccess(); + result.put("isCorrectlySpelled", isCorrectlySpelled); + + Map<String, Integer> facetQuery = queryResult.getFacetQuery(); + Map<String, String> facetQueries = FastMap.newInstance(); + for (String fq : facetQuery.keySet()) { + if (facetQuery.get(fq).intValue() > 0) + facetQueries.put(fq, fq.replaceAll("^.*\\u005B(.*)\\u005D", "$1") + " (" + facetQuery.get(fq).intValue() + ")"); + } + + Map<String, Map<String, Long>> facetFields = FastMap.newInstance(); + List<FacetField> facets = queryResult.getFacetFields(); + for (FacetField facet : facets) { + Map<String, Long> facetEntry = FastMap.newInstance(); + List<FacetField.Count> facetEntries = facet.getValues(); + if (UtilValidate.isNotEmpty(facetEntries)) { + for (FacetField.Count fcount : facetEntries) + facetEntry.put(fcount.getName(), fcount.getCount()); + facetFields.put(facet.getName(), facetEntry); + } + } + + result.put("results", queryResult.getResults()); + result.put("facetFields", facetFields); + result.put("facetQueries", facetQueries); + result.put("queryTime", queryResult.getElapsedTime()); + result.put("listSize", queryResult.getResults().getNumFound()); + result.put("viewIndex", queryResult.getResults().getStart()); + result.put("viewSize", queryResult.getResults().size()); + result.put("suggestions", suggestions); + + } catch (Exception e) { + Debug.logError(e, e.getMessage(), module); + result = ServiceUtil.returnError(e.toString()); + } + return result; + } + + /** + * Returns a map of the categories currently available under the root element. + */ + public static Map<String, Object> getAvailableCategories(DispatchContext dctx, Map<String, Object> context) { + Map<String, Object> result; + try { + boolean displayProducts = false; + if (UtilValidate.isNotEmpty(context.get("displayProducts"))) + displayProducts = (Boolean) context.get("displayProducts"); + + int viewIndex = 0; + int viewSize = 9; + if (displayProducts) { + viewIndex = (Integer) context.get("viewIndex"); + viewSize = (Integer) context.get("viewSize"); + } + String catalogId = null; + if (UtilValidate.isNotEmpty(context.get("catalogId"))) + catalogId = (String) context.get("catalogId"); + + //String productCategoryId = (String) context.get("productCategoryId") != null ? CategoryUtil.getCategoryNameWithTrail((String) context.get("productCategoryId"), dctx): null; + String productCategoryId = (String) context.get("productCategoryId") != null ? CategoryUtil.getCategoryNameWithTrail((String) context.get("productCategoryId"),dctx) : null; + Debug.logInfo("productCategoryId "+productCategoryId, module); + Map<String, Object> query = SolrUtil.categoriesAvailable(catalogId, productCategoryId, (String) context.get("productId"), displayProducts, viewIndex, viewSize); + + QueryResponse cat = (QueryResponse) query.get("rows"); + result = ServiceUtil.returnSuccess(); + result.put("numFound", (long) 0); + Map<String, Object> categories = FastMap.newInstance(); + List<FacetField> catList = (List<FacetField>) cat.getFacetFields(); + for (Iterator<FacetField> catIterator = catList.iterator(); catIterator.hasNext();) { + FacetField field = (FacetField) catIterator.next(); + List<Count> catL = (List<Count>) field.getValues(); + if (catL != null) { + // log.info("FacetFields = "+catL); + for (Iterator<Count> catIter = catL.iterator(); catIter.hasNext();) { + FacetField.Count f = (FacetField.Count) catIter.next(); + if (f.getCount() > 0) { + categories.put(f.getName(), Long.toString(f.getCount())); + } + } + result.put("categories", categories); + result.put("numFound", cat.getResults().getNumFound()); + // log.info("The returned map is this:"+result); + } + } + } catch (Exception e) { + result = ServiceUtil.returnError(e.toString()); + result.put("numFound", (long) 0); + } + return result; + } + + + /** + * Return a map of the side deep categories. + */ + public static Map<String, Object> getSideDeepCategories(DispatchContext dctx, Map<String, Object> context) { + Map<String, Object> result; + try { + String catalogId = null; + if (UtilValidate.isNotEmpty(context.get("catalogId"))) + catalogId = (String) context.get("catalogId"); + + String productCategoryId = (String) context.get("productCategoryId") != null ? CategoryUtil.getCategoryNameWithTrail((String) context.get("productCategoryId"),dctx) : null; + result = ServiceUtil.returnSuccess(); + Map<String, List<Map<String, Object>>> catLevel = FastMap.newInstance(); + Debug.logInfo("productCategoryId: "+productCategoryId, module); + + //Add toplevel categories + String[] trailElements = productCategoryId.split("/"); + + //iterate over actual results + for(String elements : trailElements){ + //catIds must be greater than 3 chars + if(elements.length()>3){ + Debug.logInfo("elements: "+elements,module); + String categoryPath = CategoryUtil.getCategoryNameWithTrail(elements,dctx); + String[] categoryPathArray = categoryPath.split("/"); + int level = Integer.parseInt(categoryPathArray[0]); + String facetQuery = CategoryUtil.getFacetFilterForCategory(categoryPath, dctx); + //Debug.logInfo("categoryPath: "+categoryPath + " facetQuery: "+facetQuery,module); + Map<String, Object> query = SolrUtil.categoriesAvailable(catalogId, categoryPath, null, facetQuery,false, 0, 0); + QueryResponse cat = (QueryResponse) query.get("rows"); + List<Map<String, Object>> categories = FastList.newInstance(); + + + List<FacetField> catList = (List<FacetField>) cat.getFacetFields(); + for (Iterator<FacetField> catIterator = catList.iterator(); catIterator.hasNext();) { + FacetField field = (FacetField) catIterator.next(); + List<Count> catL = (List<Count>) field.getValues(); + if (catL != null) { + for (Iterator<Count> catIter = catL.iterator(); catIter.hasNext();) { + FacetField.Count f = (FacetField.Count) catIter.next(); + if (f.getCount() > 0) { + Map<String, Object> catMap = FastMap.newInstance(); + FastList<String> iName = FastList.newInstance(); + iName.addAll(Arrays.asList(f.getName().split("/"))); + //Debug.logInfo("topLevel "+topLevel,""); + // int l = Integer.parseInt((String) iName.getFirst()); + catMap.put("catId",iName.getLast()); + iName.removeFirst(); + String path = f.getName(); + catMap.put("path",path); + if(level>0){ + iName.removeLast(); + catMap.put("parentCategory",StringUtils.join(iName, "/")); + }else{ + catMap.put("parentCategory",null); + } + catMap.put("count", Long.toString(f.getCount())); + categories.add(catMap); + } + } + } + } + catLevel.put("menu-"+level, categories); + } + } + result.put("categories", catLevel); + result.put("numFound", (long) 0); + + } catch (Exception e) { + result = ServiceUtil.returnError(e.toString()); + result.put("numFound", (long) 0); + } + return result; + } + + /** + * Rebuilds the solr index. + */ + public static Map<String, Object> rebuildSolrIndex(DispatchContext dctx, Map<String, Object> context) throws GenericEntityException { + HttpSolrServer server = null; + Map<String, Object> result; + GenericDelegator delegator = (GenericDelegator) dctx.getDelegator(); + LocalDispatcher dispatcher = dctx.getDispatcher(); + GenericValue userLogin = (GenericValue) context.get("userLogin"); + Locale locale = new Locale("de_DE"); + + Boolean treatConnectErrorNonFatal = (Boolean) context.get("treatConnectErrorNonFatal"); + + try { + server = new HttpSolrServer(SolrUtil.solrUrl); + + // now lets fetch all products + List<Map<String, Object>> solrDocs = FastList.newInstance(); + List<GenericValue> products = delegator.findList("Product", null, null, null, null, true); + int numDocs = 0; + if (products != null) { + numDocs = products.size(); + } + + Debug.logInfo("Solr: Clearing solr index and rebuilding with " + numDocs + " found products", module); + + Iterator<GenericValue> productIterator = products.iterator(); + while (productIterator.hasNext()) { + GenericValue product = productIterator.next(); + Map<String, Object> dispatchContext = ProductUtil.getProductContent(product, dctx, context); + solrDocs.add(dispatchContext); + } + + // this removes everything from the index + server.deleteByQuery("*:*"); + server.commit(); + + // THis adds all products to the Index (instantly) + Map<String, Object> runResult = dispatcher.runSync("addListToSolrIndex", UtilMisc.toMap("fieldList", solrDocs, "userLogin", userLogin, + "locale", locale, "treatConnectErrorNonFatal", treatConnectErrorNonFatal)); + + String runMsg = ServiceUtil.getErrorMessage(runResult); + if (UtilValidate.isEmpty(runMsg)) { + runMsg = null; + } + if (ServiceUtil.isError(runResult)) { + result = ServiceUtil.returnError(runMsg); + } + else if (ServiceUtil.isFailure(runResult)) { + result = ServiceUtil.returnFailure(runMsg); + } + else { + final String statusMsg = "Cleared solr index and reindexed " + numDocs + " documents"; + result = ServiceUtil.returnSuccess(statusMsg); + } + } catch (MalformedURLException e) { + Debug.logError(e, e.getMessage(), module); + result = ServiceUtil.returnError(e.toString()); + } catch (SolrServerException e) { + if (e.getCause() != null && e.getCause() instanceof ConnectException) { + final String statusStr = "Failure connecting to solr server to rebuild index; index not updated"; + if (Boolean.TRUE.equals(treatConnectErrorNonFatal)) { + Debug.logWarning(e, "Solr: " + statusStr, module); + result = ServiceUtil.returnFailure(statusStr); + } + else { + Debug.logError(e, "Solr: " + statusStr, module); + result = ServiceUtil.returnError(statusStr); + } + } + else { + Debug.logError(e, e.getMessage(), module); + result = ServiceUtil.returnError(e.toString()); + } + } catch (IOException e) { + Debug.logError(e, e.getMessage(), module); + result = ServiceUtil.returnError(e.toString()); + } catch (ServiceAuthException e) { + Debug.logError(e, e.getMessage(), module); + result = ServiceUtil.returnError(e.toString()); + } catch (ServiceValidationException e) { + Debug.logError(e, e.getMessage(), module); + result = ServiceUtil.returnError(e.toString()); + } catch (GenericServiceException e) { + Debug.logError(e, e.getMessage(), module); + result = ServiceUtil.returnError(e.toString()); + } catch (Exception e) { + Debug.logError(e, e.getMessage(), module); + result = ServiceUtil.returnError(e.toString()); + } + return result; + } +} Propchange: ofbiz/trunk/specialpurpose/solr/src/org/ofbiz/solr/SolrProductSearch.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: ofbiz/trunk/specialpurpose/solr/src/org/ofbiz/solr/SolrProductSearch.java ------------------------------------------------------------------------------ svn:keywords = Date Rev Author URL Id Propchange: ofbiz/trunk/specialpurpose/solr/src/org/ofbiz/solr/SolrProductSearch.java ------------------------------------------------------------------------------ svn:mime-type = text/plain |
Free forum by Nabble | Edit this page |