/***************************************************
*
* cismet GmbH, Saarbruecken, Germany
*
* ... and it just works.
*
****************************************************/
/*
* Copyright (C) 2010 thorsten
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package Sirius.server.search.builtin;
import Sirius.server.middleware.interfaces.domainserver.MetaService;
import Sirius.server.middleware.types.MetaObjectNode;
import Sirius.server.middleware.types.Node;
import Sirius.server.search.CidsServerSearch;
import com.vividsolutions.jts.geom.Geometry;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
/**
* DOCUMENT ME!
*
* @author thorsten
* @version $Revision$, $Date$
*/
public class FullTextSearch extends CidsServerSearch {
//~ Instance fields --------------------------------------------------------
private String searchText;
private boolean caseSensitive;
private Geometry geometry;
private GeoSearch geoSearch;
//~ Constructors -----------------------------------------------------------
/**
* Creates a new FullTextSearch object.
*
* @param searchText The text to search for.
* @param caseSensitive A flag indicating whether to make the search case sensitive or not.
*/
public FullTextSearch(final String searchText, final boolean caseSensitive) {
this(searchText, caseSensitive, null);
}
/**
* Creates a new FullTextSearch object.
*
* @param searchText The text to search for.
* @param caseSensitive A flag indicating whether to make the search case sensitive or not.
* @param geometry The search will be restricted to the given geometry.
*/
public FullTextSearch(final String searchText, final boolean caseSensitive, final Geometry geometry) {
this.searchText = searchText;
this.caseSensitive = caseSensitive;
this.geometry = geometry;
if (geometry != null) {
geoSearch = new GeoSearch(geometry);
}
}
//~ Methods ----------------------------------------------------------------
@Override
public Collection performServerSearch() {
try {
getLog().info("FullTextSearch started");
final String caseSensitiveI = (caseSensitive) ? "" : "I"; // Ein I vor LIKE macht die Suche case insensitive
final String geoPrefix = "\n select distinct * from ( ";
final String sql = ""
+ "SELECT DISTINCT i.class_id ocid,i.object_id as oid, c.stringrep "
+ "FROM cs_attr_string s, "
+ " cs_attr_object_derived i "
+ " LEFT OUTER JOIN cs_stringrepcache c "
+ " ON ( "
+ " c.class_id =i.class_id "
+ " AND c.object_id=i.object_id "
+ " ) "
+ "WHERE i.attr_class_id = s.class_id "
+ "AND i.attr_object_id=s.object_id "
+ "AND s.string_val " + caseSensitiveI + "like '%<cidsSearchText>%' "
+ "AND i.class_id IN <cidsClassesInStatement>";
final String altsql = "select distinct ocid,oid,stringrep from "
+ "\n(WITH recursive derived_index(ocid,oid,acid,aid,depth) AS "
+ "\n( SELECT class_id , "
+ "\n object_id , "
+ "\n class_id , "
+ "\n object_id , "
+ "\n 0 "
+ "\nFROM textsearch "
+ "\nWHERE class_id IN ( WITH recursive derived_child(father,child,depth) AS "
+ "\n ( SELECT father, "
+ "\n father , "
+ "\n 0 "
+ "\n FROM cs_class_hierarchy "
+ "\n WHERE father IN <cidsClassesInStatement> "
+ "\n "
+ "\n UNION ALL "
+ "\n "
+ "\n SELECT ch.father, "
+ "\n ch.child , "
+ "\n dc.depth+1 "
+ "\n FROM derived_child dc, "
+ "\n cs_class_hierarchy ch "
+ "\n WHERE ch.father=dc.child "
+ "\n ) "
+ "\n SELECT DISTINCT child "
+ "\n FROM derived_child LIMIT 100000 ) "
+ "\nAND string_val " + caseSensitiveI + "LIKE '%<cidsSearchText>%' "
+ "\n "
+ "\nUNION ALL "
+ "\n "
+ "\nSELECT aam.class_id , "
+ "\n aam.object_id , "
+ "\n aam.attr_class_id , "
+ "\n aam.attr_object_id, "
+ "\n di.depth+1 "
+ "\nFROM cs_attr_object aam, "
+ "\n derived_index di "
+ "\nWHERE aam.attr_class_id =di.ocid AND"
+ "\n aam.attr_object_id=di.oid "
+ "\n) "
+ "\nSELECT ocid,oid,stringrep "
+ "\nFROM derived_index left outer join cs_stringrepcache on ocid=class_id AND oid =object_id "
+ "\nWHERE ocid IN <cidsClassesInStatement> LIMIT 10000000) as x";
final String geoMidFix = "\n ) as txt,(select distinct class_id as ocid,object_id as oid,stringrep from (";
final String geoPostfix = "\n )as y ) as geo "
+ "\n where txt.ocid=geo.ocid and txt.oid=geo.oid";
// Deppensuche sequentiell
final HashSet keyset = new HashSet(getActiveLoaclServers().keySet());
final ArrayList<Node> aln = new ArrayList<Node>();
if (geometry != null) {
geoSearch.setClassesInSnippetsPerDomain(getClassesInSnippetsPerDomain());
}
for (final Object key : keyset) {
final MetaService ms = (MetaService)getActiveLoaclServers().get(key);
final String classesInStatement = getClassesInSnippetsPerDomain().get((String)key);
if (classesInStatement != null) {
String sqlStatement = sql.replaceAll("<cidsClassesInStatement>", classesInStatement)
.replaceAll("<cidsSearchText>", searchText);
if (geometry != null) {
final String geoSql = geoSearch.getGeoSearchSql(key);
if (geoSql != null) {
sqlStatement = geoPrefix + sqlStatement + geoMidFix + geoSql + geoPostfix;
}
}
if (getLog().isDebugEnabled()) {
getLog().debug(sqlStatement);
}
final ArrayList<ArrayList> result = ms.performCustomSearch(sqlStatement);
for (final ArrayList al : result) {
final int cid = (Integer)al.get(0);
final int oid = (Integer)al.get(1);
String name = null;
try {
name = (String)al.get(2);
} catch (Exception e) {
}
final MetaObjectNode mon = new MetaObjectNode((String)key, oid, cid, name);
aln.add(mon);
}
}
}
return aln;
} catch (Exception e) {
getLog().fatal("Problem bei der Volltextsuche", e);
return null;
}
}
}