[hibernate-commits] Hibernate SVN: r20176 - in search/trunk/hibernate-search/src: main/java/org/hibernate/search/impl and 4 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Thu Aug 19 07:45:48 EDT 2010


Author: hardy.ferentschik
Date: 2010-08-19 07:45:48 -0400 (Thu, 19 Aug 2010)
New Revision: 20176

Modified:
   search/trunk/hibernate-search/src/main/java/org/hibernate/search/Environment.java
   search/trunk/hibernate-search/src/main/java/org/hibernate/search/SearchFactory.java
   search/trunk/hibernate-search/src/main/java/org/hibernate/search/impl/ImmutableSearchFactory.java
   search/trunk/hibernate-search/src/main/java/org/hibernate/search/impl/MutableSearchFactory.java
   search/trunk/hibernate-search/src/main/java/org/hibernate/search/jmx/StatisticsImpl.java
   search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/FullTextQueryImpl.java
   search/trunk/hibernate-search/src/main/java/org/hibernate/search/stat/Statistics.java
   search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/batchindexing/IndexingGeneratedCorpusTest.java
Log:
HSEARCH-278 Introduced a Statistics interface and implementation. Also exposed it via JMX

Modified: search/trunk/hibernate-search/src/main/java/org/hibernate/search/Environment.java
===================================================================
--- search/trunk/hibernate-search/src/main/java/org/hibernate/search/Environment.java	2010-08-19 11:44:21 UTC (rev 20175)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/Environment.java	2010-08-19 11:45:48 UTC (rev 20176)
@@ -121,9 +121,13 @@
 	public static final String ERROR_HANDLER = "hibernate.search.error_handler";
 
 	/**
-	 * If set to {@code true} the JMX Statistics bean gets enabled. For all other values the bean does not
+	 * If set to {@code true} JMX beans get enabled. For all other values the beans do not.
 	 * get enabled.
 	 */
 	public static final String JMX_ENABLED = "hibernate.search.jmx_enabled";
 
+	/**
+	 * If set to {@code true} the search statistic will be gathered.
+	 */
+	public static final String GENERATE_STATS = "hibernate.search.generate_statistics";
 }

Modified: search/trunk/hibernate-search/src/main/java/org/hibernate/search/SearchFactory.java
===================================================================
--- search/trunk/hibernate-search/src/main/java/org/hibernate/search/SearchFactory.java	2010-08-19 11:44:21 UTC (rev 20175)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/SearchFactory.java	2010-08-19 11:45:48 UTC (rev 20176)
@@ -28,10 +28,12 @@
 
 import org.hibernate.search.query.dsl.v2.QueryContextBuilder;
 import org.hibernate.search.reader.ReaderProvider;
+import org.hibernate.search.stat.Statistics;
 import org.hibernate.search.store.DirectoryProvider;
 
 /**
  * Provide application wide operations as well as access to the underlying Lucene resources.
+ *
  * @author Emmanuel Bernard
  */
 public interface SearchFactory {
@@ -63,18 +65,20 @@
 	/**
 	 * Experimental API
 	 * retrieve an analyzer instance by its definition name
-	 * 
+	 *
 	 * @throws SearchException if the definition name is unknown
 	 */
 	Analyzer getAnalyzer(String name);
-	
+
 	/**
 	 * Retrieves the scoped analyzer for a given class.
-	 * 
+	 *
 	 * @param clazz The class for which to retrieve the analyzer.
+	 *
 	 * @return The scoped analyzer for the specified class.
+	 *
 	 * @throws IllegalArgumentException in case <code>clazz == null</code> or the specified
-	 * class is not an indexed entity.
+	 *                                  class is not an indexed entity.
 	 */
 	Analyzer getAnalyzer(Class<?> clazz);
 
@@ -82,4 +86,11 @@
 	 * Return a query builder providing a fluent API to create Lucene queries
 	 */
 	QueryContextBuilder buildQueryBuilder();
+
+	/**
+	 * Retrieve the statistics for this factory.
+	 *
+	 * @return The statistics.
+	 */
+	public Statistics getStatistics();
 }

Modified: search/trunk/hibernate-search/src/main/java/org/hibernate/search/impl/ImmutableSearchFactory.java
===================================================================
--- search/trunk/hibernate-search/src/main/java/org/hibernate/search/impl/ImmutableSearchFactory.java	2010-08-19 11:44:21 UTC (rev 20175)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/impl/ImmutableSearchFactory.java	2010-08-19 11:45:48 UTC (rev 20176)
@@ -56,6 +56,9 @@
 import org.hibernate.search.engine.SearchFactoryImplementor;
 import org.hibernate.search.exception.ErrorHandler;
 import org.hibernate.search.filter.FilterCachingStrategy;
+import org.hibernate.search.jmx.JMXRegistrar;
+import org.hibernate.search.jmx.StatisticsImpl;
+import org.hibernate.search.jmx.StatisticsImplMBean;
 import org.hibernate.search.query.dsl.v2.QueryContextBuilder;
 import org.hibernate.search.query.dsl.v2.impl.ConnectedQueryContextBuilder;
 import org.hibernate.search.reader.ReaderProvider;
@@ -63,6 +66,7 @@
 import org.hibernate.search.spi.internals.DirectoryProviderData;
 import org.hibernate.search.spi.internals.PolymorphicIndexHierarchy;
 import org.hibernate.search.spi.internals.StateSearchFactoryImplementor;
+import org.hibernate.search.stat.Statistics;
 import org.hibernate.search.store.DirectoryProvider;
 import org.hibernate.search.store.optimization.OptimizerStrategy;
 import org.hibernate.search.util.LoggerFactory;
@@ -97,6 +101,7 @@
 	private final Properties configurationProperties;
 	private final ErrorHandler errorHandler;
 	private final PolymorphicIndexHierarchy indexHierarchy;
+	private final Statistics statistics;
 
 	/**
 	 * Each directory provider (index) can have its own performance settings.
@@ -120,6 +125,16 @@
 		this.indexingStrategy = cfg.indexingStrategy;
 		this.readerProvider = cfg.readerProvider;
 		this.worker = cfg.worker;
+		this.statistics = new StatisticsImpl();
+		String enableStats = configurationProperties.getProperty( Environment.JMX_ENABLED );
+		if ( "true".equalsIgnoreCase( enableStats ) ) {
+			statistics.setStatisticsEnabled( true );
+		}
+
+		String enableJMX = configurationProperties.getProperty( Environment.JMX_ENABLED );
+		if ( "true".equalsIgnoreCase( enableJMX ) ) {
+			JMXRegistrar.registerMBean( statistics, StatisticsImplMBean.STATISTICS_MBEAN_OBJECT_NAME );
+		}
 	}
 
 	public BackendQueueProcessorFactory getBackendQueueProcessorFactory() {
@@ -264,6 +279,10 @@
 		return new ConnectedQueryContextBuilder( this );
 	}
 
+	public Statistics getStatistics() {
+		return statistics;
+	}
+
 	public FilterCachingStrategy getFilterCachingStrategy() {
 		return filterCachingStrategy;
 	}

Modified: search/trunk/hibernate-search/src/main/java/org/hibernate/search/impl/MutableSearchFactory.java
===================================================================
--- search/trunk/hibernate-search/src/main/java/org/hibernate/search/impl/MutableSearchFactory.java	2010-08-19 11:44:21 UTC (rev 20175)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/impl/MutableSearchFactory.java	2010-08-19 11:45:48 UTC (rev 20176)
@@ -25,6 +25,7 @@
 import org.hibernate.search.spi.internals.DirectoryProviderData;
 import org.hibernate.search.spi.internals.PolymorphicIndexHierarchy;
 import org.hibernate.search.spi.internals.StateSearchFactoryImplementor;
+import org.hibernate.search.stat.Statistics;
 import org.hibernate.search.store.DirectoryProvider;
 import org.hibernate.search.store.optimization.OptimizerStrategy;
 
@@ -180,6 +181,10 @@
 		return delegate.buildQueryBuilder();
 	}
 
+	public Statistics getStatistics() {
+		return delegate.getStatistics();
+	}
+
 	public Map<Class<?>, DocumentBuilderContainedEntity<?>> getDocumentBuildersContainedEntities() {
 		return delegate.getDocumentBuildersContainedEntities();
 	}

Modified: search/trunk/hibernate-search/src/main/java/org/hibernate/search/jmx/StatisticsImpl.java
===================================================================
--- search/trunk/hibernate-search/src/main/java/org/hibernate/search/jmx/StatisticsImpl.java	2010-08-19 11:44:21 UTC (rev 20175)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/jmx/StatisticsImpl.java	2010-08-19 11:45:48 UTC (rev 20176)
@@ -24,41 +24,60 @@
 package org.hibernate.search.jmx;
 
 import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
 
-import org.hibernate.search.jmx.StatisticsImplMBean;
-import org.hibernate.search.stat.Statistics;
-
 /**
  * @author Hardy Ferentschik
  */
-public class StatisticsImpl implements Statistics, StatisticsImplMBean {
+public class StatisticsImpl implements StatisticsImplMBean {
 	private AtomicLong searchQueryCount = new AtomicLong();
-	private AtomicLong searchExecutionAvgTime = new AtomicLong();
 	private AtomicLong searchExecutionTotalTime = new AtomicLong();
 	private AtomicLong searchExecutionMaxTime = new AtomicLong();
-	private AtomicLong searchExecutionMinTime = new AtomicLong();
 	private volatile String queryExecutionMaxTimeQueryString;
 	private volatile boolean isStatisticsEnabled;
 
+	private final Lock readLock;
+	private final Lock writeLock;
 
+	{
+		ReadWriteLock lock = new ReentrantReadWriteLock();
+		readLock = lock.readLock();
+		writeLock = lock.writeLock();
+	}
+
 	public void clear() {
 		searchQueryCount.set( 0 );
+		searchExecutionTotalTime.set( 0 );
+		searchExecutionMaxTime.set( 0 );
+		queryExecutionMaxTimeQueryString = "";
 	}
 
 	public long getSearchQueryExecutionCount() {
 		return searchQueryCount.get();
 	}
 
+	public long getSearchQueryTotalTime() {
+		return searchExecutionTotalTime.get();
+	}
+
 	public long getSearchQueryExecutionMaxTime() {
 		return searchExecutionMaxTime.get();
 	}
 
-	public long getSearchQueryExecutionMinTime() {
-		return searchExecutionMinTime.get();
-	}
-
 	public long getSearchQueryExecutionAvgTime() {
-		return searchExecutionAvgTime.get();
+		writeLock.lock();
+		try {
+			long avgExecutionTime = 0;
+			if ( searchQueryCount.get() > 0 ) {
+				avgExecutionTime = searchExecutionTotalTime.get() / searchQueryCount.get();
+			}
+			return avgExecutionTime;
+		}
+		finally {
+			writeLock.unlock();
+		}
 	}
 
 	public String getSearchQueryExecutionMaxTimeQueryString() {
@@ -66,26 +85,23 @@
 	}
 
 	public void searchExecuted(String searchString, long time) {
-		searchQueryCount.getAndIncrement();
-		boolean isLongestQuery = false;
-		for ( long old = searchExecutionMaxTime.get();
-			  ( time > old ) && ( isLongestQuery = !searchExecutionMaxTime.compareAndSet( old, time ) );
-			  old = searchExecutionMaxTime.get() ) {
-			;
+		readLock.lock();
+		try {
+			boolean isLongestQuery = false;
+			for ( long old = searchExecutionMaxTime.get();
+				  ( time > old ) && ( isLongestQuery = searchExecutionMaxTime.compareAndSet( old, time ) );
+				  old = searchExecutionMaxTime.get() ) {
+				;
+			}
+			if ( isLongestQuery ) {
+				queryExecutionMaxTimeQueryString = searchString;
+			}
+			searchQueryCount.getAndIncrement();
+			searchExecutionTotalTime.addAndGet( time );
 		}
-		if ( isLongestQuery ) {
-			queryExecutionMaxTimeQueryString = searchString;
+		finally {
+			readLock.unlock();
 		}
-
-		boolean isShortestQuery = false;
-		for ( long old = searchExecutionMinTime.get();
-			  ( time < old ) && ( isShortestQuery = !searchExecutionMinTime.compareAndSet( old, time ) );
-			  old = searchExecutionMinTime.get() ) {
-			;
-		}
-
-		searchExecutionTotalTime.getAndAdd( time );
-		searchExecutionAvgTime.getAndSet( searchExecutionTotalTime.get() / searchQueryCount.get() );
 	}
 
 	public boolean isStatisticsEnabled() {

Modified: search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/FullTextQueryImpl.java
===================================================================
--- search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/FullTextQueryImpl.java	2010-08-19 11:44:21 UTC (rev 20175)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/query/FullTextQueryImpl.java	2010-08-19 11:45:48 UTC (rev 20176)
@@ -53,11 +53,11 @@
 import org.hibernate.Criteria;
 import org.hibernate.HibernateException;
 import org.hibernate.LockMode;
+import org.hibernate.LockOptions;
 import org.hibernate.Query;
 import org.hibernate.ScrollMode;
 import org.hibernate.ScrollableResults;
 import org.hibernate.Session;
-import org.hibernate.LockOptions;
 import org.hibernate.engine.SessionImplementor;
 import org.hibernate.engine.query.ParameterMetadata;
 import org.hibernate.impl.AbstractQueryImpl;
@@ -77,24 +77,21 @@
 import org.hibernate.search.engine.SearchFactoryImplementor;
 import org.hibernate.search.filter.ChainedFilter;
 import org.hibernate.search.filter.FilterKey;
-import org.hibernate.search.filter.StandardFilterKey;
 import org.hibernate.search.filter.FullTextFilterImplementor;
 import org.hibernate.search.filter.ShardSensitiveOnlyFilter;
+import org.hibernate.search.filter.StandardFilterKey;
 import org.hibernate.search.reader.ReaderProvider;
-
-import static org.hibernate.search.reader.ReaderProviderHelper.getIndexReaders;
-
 import org.hibernate.search.store.DirectoryProvider;
 import org.hibernate.search.store.IndexShardingStrategy;
 import org.hibernate.search.util.ContextHelper;
+import org.hibernate.search.util.LoggerFactory;
+import org.hibernate.transform.ResultTransformer;
+import org.hibernate.util.ReflectHelper;
 
+import static org.hibernate.search.reader.ReaderProviderHelper.getIndexReaders;
 import static org.hibernate.search.util.FilterCacheModeTypeHelper.cacheInstance;
 import static org.hibernate.search.util.FilterCacheModeTypeHelper.cacheResults;
 
-import org.hibernate.search.util.LoggerFactory;
-import org.hibernate.transform.ResultTransformer;
-import org.hibernate.util.ReflectHelper;
-
 /**
  * Implementation of {@link org.hibernate.search.FullTextQuery}.
  *
@@ -401,6 +398,13 @@
 		org.apache.lucene.search.Query query = filterQueryByClasses( luceneQuery );
 		buildFilters();
 		QueryHits queryHits;
+
+		boolean stats = searchFactoryImplementor.getStatistics().isStatisticsEnabled();
+		long startTime = 0;
+		if ( stats ) {
+			startTime = System.currentTimeMillis();
+		}
+
 		if ( n == null ) { // try to make sure that we get the right amount of top docs
 			queryHits = new QueryHits( searcher, query, filter, sort );
 		}
@@ -408,6 +412,11 @@
 			queryHits = new QueryHits( searcher, query, filter, sort, n );
 		}
 		resultSize = queryHits.totalHits;
+
+		if ( stats ) {
+			searchFactoryImplementor.getStatistics().searchExecuted( query.toString(), System.currentTimeMillis() - startTime );
+		}
+
 		return queryHits;
 	}
 
@@ -902,10 +911,10 @@
 	}
 
 	public <T> T unwrap(Class<T> type) {
-		if ( type == org.apache.lucene.search.Query.class) {
-			return (T) luceneQuery;
+		if ( type == org.apache.lucene.search.Query.class ) {
+			return ( T ) luceneQuery;
 		}
-		throw new IllegalArgumentException("Cannot unwrap " + type.getName() );
+		throw new IllegalArgumentException( "Cannot unwrap " + type.getName() );
 	}
 
 	public LockOptions getLockOptions() {

Modified: search/trunk/hibernate-search/src/main/java/org/hibernate/search/stat/Statistics.java
===================================================================
--- search/trunk/hibernate-search/src/main/java/org/hibernate/search/stat/Statistics.java	2010-08-19 11:44:21 UTC (rev 20175)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/stat/Statistics.java	2010-08-19 11:45:48 UTC (rev 20176)
@@ -1,10 +1,75 @@
-// $Id:$
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ *  Copyright (c) 2010, Red Hat, Inc. and/or its affiliates or third-party contributors as
+ *  indicated by the @author tags or express copyright attribution
+ *  statements applied by the authors.  All third-party contributions are
+ *  distributed under license by Red Hat, Inc.
+ *
+ *  This copyrighted material is made available to anyone wishing to use, modify,
+ *  copy, or redistribute it subject to the terms and conditions of the GNU
+ *  Lesser General Public License, as published by the Free Software Foundation.
+ *
+ *  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 Lesser General Public License
+ *  for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public License
+ *  along with this distribution; if not, write to:
+ *  Free Software Foundation, Inc.
+ *  51 Franklin Street, Fifth Floor
+ *  Boston, MA  02110-1301  USA
+ */
 package org.hibernate.search.stat;
 
 /**
  * @author Hardy Ferentschik
  */
-public class Statistics {
+public interface Statistics {
+	/**
+	 * Reset all statistics.
+	 */
+	void clear();
+
+	/**
+	 * Get global number of executed search queries
+	 *
+	 * @return search query execution count
+	 */
+	long getSearchQueryExecutionCount();
+
+	/**
+	 * Get the total search time in milliseconds.
+	 */
+	long getSearchQueryTotalTime();	
+
+	/**
+	 * Get the time in milliseconds of the slowest search.
+	 */
+	long getSearchQueryExecutionMaxTime();
+
+	/**
+	 * Get the average search time in milliseconds.
+	 */
+	long getSearchQueryExecutionAvgTime();
+
+	/**
+	 * Get the query string for the slowest query.
+	 */
+	String getSearchQueryExecutionMaxTimeQueryString();
+
+	void searchExecuted(String searchString, long time);
+
+	/**
+	 * Are statistics logged
+	 */
+	public boolean isStatisticsEnabled();
+
+	/**
+	 * Enable statistics logs (this is a dynamic parameter)
+	 */
+	public void setStatisticsEnabled(boolean b);
 }
 
 

Modified: search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/batchindexing/IndexingGeneratedCorpusTest.java
===================================================================
--- search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/batchindexing/IndexingGeneratedCorpusTest.java	2010-08-19 11:44:21 UTC (rev 20175)
+++ search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/batchindexing/IndexingGeneratedCorpusTest.java	2010-08-19 11:45:48 UTC (rev 20176)
@@ -70,6 +70,7 @@
 				.setProperty( "hibernate.jndi.org.osjava.sj.root", "/Users/hardy/tmp/jndi-entries" )
 				.setProperty( "hibernate.jndi.org.osjava.sj.jndi.shared", "true" )
 				.setProperty( Environment.JMX_ENABLED, "true" )
+				.setProperty( Environment.GENERATE_STATS, "true" )
 				.build();
 		createMany( Book.class, BOOK_NUM );
 		createMany( Dvd.class, DVD_NUM );



More information about the hibernate-commits mailing list