Browse Source

style, comments, bugfixes


git-svn-id: svn://svn.sphinxsearch.com/sphinx/trunk@903 406a0c4d-033a-0410-8de8-e80135713968
shodan 18 years ago
parent
commit
7df7aa1260

+ 1 - 1
api/java/Makefile

@@ -5,7 +5,7 @@
 #
 
 PASS1SOURCES = \
-	SphinxDocInfo.java \
+	SphinxMatch.java \
 	SphinxException.java \
 	SphinxResult.java \
 	SphinxWordInfo.java

+ 132 - 272
api/java/SphinxClient.java

@@ -61,18 +61,18 @@ public class SphinxClient
 
 	/* searchd commands */
 	private final static int SEARCHD_COMMAND_SEARCH	= 0;
-	private final static int SEARCHD_COMMAND_EXCERPT	= 1;
+	private final static int SEARCHD_COMMAND_EXCERPT= 1;
 	private final static int SEARCHD_COMMAND_UPDATE	= 2;
 
 	/* searchd command versions */
-	private final static int VER_MAJOR_PROTO			= 0x1;
+	private final static int VER_MAJOR_PROTO		= 0x1;
 	private final static int VER_COMMAND_SEARCH		= 0x10F;
-	private final static int VER_COMMAND_EXCERPT		= 0x100;
+	private final static int VER_COMMAND_EXCERPT	= 0x100;
 	private final static int VER_COMMAND_UPDATE		= 0x100;
 
 	/* filter types */
 	private final static int SPH_FILTER_VALUES		= 0;
-	private final static int SPH_FILTER_RANGE			= 1;
+	private final static int SPH_FILTER_RANGE		= 1;
 	private final static int SPH_FILTER_FLOATRANGE	= 2;
 
 
@@ -164,7 +164,7 @@ public class SphinxClient
 
 		_reqs			= new ArrayList();
 		_weights		= null;
-		_indexWeights = new LinkedHashMap();
+		_indexWeights	= new LinkedHashMap();
 	}
 
 	/**
@@ -180,7 +180,7 @@ public class SphinxClient
 	/**
 	 * Get last warning message, if any.
 	 *
-	 * @return string with last error message (empty string if no errors occured)
+	 * @return string with last warning message (empty string if no errors occured)
 	 */
 	public String GetLastWarning()
 	{
@@ -203,12 +203,7 @@ public class SphinxClient
 		_port = port;
 	}
 
-	/**
-	 * Connect to searchd server.
-	 * Sets internal <code>_error<code> on falure
-	 *
-	 * @return open socket on success, <code>null</code> on falure.
-	 */
+	/** Connect to searchd and exchange versions (internal method). */
 	private Socket _Connect()
 	{
 		Socket sock;
@@ -216,7 +211,7 @@ public class SphinxClient
 			sock = new Socket(_host, _port);
 			sock.setSoTimeout(SPH_CLIENT_TIMEOUT_MILLISEC);
 		} catch (IOException e) {
-			_error = "connection to " + _host + ":" + _port + " failed:" + e.getMessage();
+			_error = "connection to " + _host + ":" + _port + " failed: " + e.getMessage();
 			return null;
 		}
 
@@ -229,7 +224,7 @@ public class SphinxClient
 			int version = sIn.readInt();
 			if (version < 1) {
 				sock.close();
-				_error = "expected searchd protocol version 1+, got version '" + version + "'";
+				_error = "expected searchd protocol version 1+, got version " + version;
 				return null;
 			}
 			sOut = new DataOutputStream(sockOutput);
@@ -244,18 +239,9 @@ public class SphinxClient
 			return null;
 		}
 		return sock;
-
 	}
 
-	/**
-	 * Get and check response packet from searchd server.
-	 *
-	 * @param sock socket to read from
-	 * @param client_ver searchd client version
-	 * @return raw byte response
-	 *
-	 * @throws SphinxException on invalid parameters
-	 */
+	/** Get and check response packet from searchd (internal method). */
 	private byte[] _GetResponse(Socket sock, int client_ver) throws SphinxException
 	{
 		short status = 0, ver = 0;
@@ -354,20 +340,11 @@ public class SphinxClient
 		return response;
 	}
 
-	/**
-	 * Set match offset, count, max number and cutoff
-	 *
-	 * @param offset result offset
-	 * @param limit return limit items from result set
-	 * @param max	override <code>max_matches</code> option from searchd config
-	 * @param cutoff when to stop searching
-	 *
-	 * @throws SphinxException on invalid parameters
-	 */
-	public void SetLimits(int offset, int limit, int max, int cutoff) throws SphinxException
+	/** Set matches offset and limit to return to client, max matches to retrieve on server, and cutoff. */
+	public void SetLimits ( int offset, int limit, int max, int cutoff ) throws SphinxException
 	{
 		myAssert ( offset>=0, "offset must be greater than or equal to 0" );
-		myAssert ( limit>0, "limit must be greater than 0"  );
+		myAssert ( limit>0, "limit must be greater than 0" );
 		myAssert ( max>0, "max must be greater than 0" );
 		myAssert ( cutoff>=0, "max must be greater than or equal to 0" );
 
@@ -377,40 +354,19 @@ public class SphinxClient
 		_cutoff = cutoff;
 	}
 
-	/**
-	 * Set search limits with default cutoff
-	 *
-	 * @param offset result offset
-	 * @param limit return limit items from result set
-	 * @param max	override <code>max_matches</code> option from searchd config
-	 *
-	 * @throws SphinxException on invalid parameters
-	 */
-	public void SetLimits(int offset, int limit, int max) throws SphinxException
+	/** Set matches offset and limit to return to client, and max matches to retrieve on server. */
+	public void SetLimits ( int offset, int limit, int max ) throws SphinxException
 	{
-		SetLimits(offset, limit, max, 0);
+		SetLimits ( offset, limit, max, 0 );
 	}
 
-	/**
-	 * Set search limits with default cutoff and max matches
-	 *
-	 * @param offset result offset
-	 * @param limit return limit items from result set
-	 *
-	 * @throws SphinxException on invalid parameters
-	 */
-	public void SetLimits(int offset, int limit) throws SphinxException
+	/** Set matches offset and limit to return to client. */
+	public void SetLimits ( int offset, int limit) throws SphinxException
 	{
-		SetLimits(offset, limit, 0, 0);
+		SetLimits ( offset, limit, 0, 0 );
 	}
 
-	/**
-	 * Set match mode.
-	 *
-	 * @param mode new match mode (MUST be one of SphinxClient.SPH_MATCH_* constants)
-	 *
-	 * @throws SphinxException on invalid parameters
-	 */
+	/** Set matching mode. */
 	public void SetMatchMode(int mode) throws SphinxException
 	{
 		myAssert (
@@ -422,15 +378,8 @@ public class SphinxClient
 		_mode = mode;
 	}
 
-	/**
-	 * Set sort mode.
-	 *
-	 * @param mode sort mode (MUST be one of SphinxClient.SPH_SORT_* constants)
-	 * @param sortby field to use with sort
-	 *
-	 * @throws SphinxException on invalid parameters
-	 */
-	public void SetSortMode(int mode, String sortby) throws SphinxException
+	/** Set sorting mode. */
+	public void SetSortMode ( int mode, String sortby ) throws SphinxException
 	{
 		myAssert (
 			mode==SPH_SORT_RELEVANCE ||
@@ -444,26 +393,7 @@ public class SphinxClient
 		_sortby = ( sortby==null ) ? "" : sortby;
 	}
 
-	/**
-	 * Set sort mode
-	 *
-	 * @param mode sort mode
-	 *
-	 * @throws SphinxException on invalid parameters
-	 */
-	public void SetSortMode(int mode) throws SphinxException
-	{
-		SetSortMode(mode, null);
-	}
-
-	/**
-	 * Set per-field weights.
-	 * Currently supported weights from 1 to 2^31-1. This range may change in furute.
-	 *
-	 * @param weights int array should contain positive weight
-	 *
-	 * @throws SphinxException on invalid parameters
-	 */
+	/** Set per-field weights (all values must be positive). */
 	public void SetWeights(int[] weights) throws SphinxException
 	{
 		myAssert ( weights!=null, "weights must not be null" );
@@ -475,26 +405,28 @@ public class SphinxClient
 	}
 
 	/**
-	 * set per-index weights
+	 * Set per-index weights
 	 *
-	 * @param indexWeights Map <String, Integer> with IndexName => Weight pair
+	 * @param indexWeights hash which maps String index names to Integer weights
 	 */
-	public void SetIndexWeights(Map indexWeights)
+	public void SetIndexWeights ( Map indexWeights ) throws SphinxException
 	{
+		/* FIXME! implement checks here */
 		_indexWeights = indexWeights;
 	}
 
 	/**
-	 * set IDs range to match.
-	 * Only match those records where document ID
-	 * is beetwen min and max (including min and max)
+	 * Set document IDs range to match.
 	 *
-	 * @param min min id to match
-	 * @param max max id to match
+	 * Only match those documents where document ID is beetwen given
+	 * min and max values (including themselves).
+	 *
+	 * @param min minimum document ID to match
+	 * @param max maximum document ID to match
 	 *
 	 * @throws SphinxException on invalid parameters
 	 */
-	public void SetIDRange(int min, int max) throws SphinxException
+	public void SetIDRange ( int min, int max ) throws SphinxException
 	{
 		myAssert ( min<=max, "min must be less or equal to max" );
 		_minId = min;
@@ -503,52 +435,58 @@ public class SphinxClient
 
 	/**
 	 * Set values filter.
-	 * only match those records where $attribute column values
-	 * are in specified set
 	 *
-	 * @param attribute attribute name
-	 * @param values	values to match
-	 * @param exclude invert matches
+	 * Only match those documents where <code>attribute</code> column value
+	 * is in given values set.
+	 *
+	 * @param attribute		attribute name to filter by
+	 * @param values		values set to match the attribute value by
+	 * @param exclude		whether to exclude matching documents instead
 	 *
 	 * @throws SphinxException on invalid parameters
 	 */
-	public void SetFilter(String attribute, int[] values, boolean exclude) throws SphinxException
+	public void SetFilter ( String attribute, int[] values, boolean exclude ) throws SphinxException
 	{
 		myAssert ( values!=null && values.length>0, "values array must not be null or empty" );
 		myAssert ( attribute!=null && attribute.length()>0, "attribute name must not be null or empty" );
 
 		try
 		{
-			writeNetUTF8(_filters, attribute);
-			_filters.writeInt(SPH_FILTER_VALUES);
-			_filters.writeInt(values.length);
-			for (int i = 0; i < values.length; i++)
-				_filters.writeInt(values[i]);
-			_filters.writeInt(exclude ? 1 : 0);
-		} catch (Exception e)
+			writeNetUTF8 ( _filters, attribute );
+			_filters.writeInt ( SPH_FILTER_VALUES );
+			_filters.writeInt ( values.length );
+			for ( int i=0; i<values.length; i++ )
+				_filters.writeInt ( values[i] );
+			_filters.writeInt ( exclude ? 1 : 0 );
+
+		} catch ( Exception e )
 		{
 			myAssert ( false, "IOException: " + e.getMessage() );
 		}
 		_filterCount++;
 	}
 
-	public void SetFilter(String attribute, int value, boolean exclude) throws SphinxException
+	/**
+	 * Set values filter with a single value (syntax sugar).
+	 *
+	 * @see SetFilter ( String attribute, int[] values, boolean exclude )
+	 */
+	public void SetFilter ( String attribute, int value, boolean exclude ) throws SphinxException
 	{
-		int[] values = new int[]{value};
-		SetFilter(attribute, values, exclude);
+		int[] values = new int[] { value };
+		SetFilter ( attribute, values, exclude );
 	}
 
 	/**
 	 * Set integer range filter.
 	 *
-	 * Only match those records where <code>attribute</code> column values
-	 * is beetwen <code>min</code> and <code>max</code> (including
-	 * <code>min</code> and <code>max</code>)
+	 * Only match those documents where <code>attribute</code> column value
+	 * is beetwen given min and max values (including themselves).
 	 *
 	 * @param attribute		attribute name to filter by
 	 * @param min			min attribute value
 	 * @param max			max attribute value
-	 * @param exclude		exclude-filter or include-filter flag
+	 * @param exclude		whether to exclude matching documents instead
 	 *
 	 * @throws SphinxException on invalid parameters
 	 */
@@ -557,12 +495,13 @@ public class SphinxClient
 		myAssert ( min<=max, "min must be less or equal to max" );
 		try
 		{
-			writeNetUTF8(_filters, attribute);
-			_filters.writeInt(SPH_FILTER_RANGE);
-			_filters.writeInt(min);
-			_filters.writeInt(max);
-			_filters.writeInt(exclude ? 1 : 0);
-		} catch (Exception e)
+			writeNetUTF8 ( _filters, attribute );
+			_filters.writeInt ( SPH_FILTER_RANGE );
+			_filters.writeInt ( min );
+			_filters.writeInt ( max );
+			_filters.writeInt ( exclude ? 1 : 0 );
+
+		} catch ( Exception e )
 		{
 			myAssert ( false, "IOException: " + e.getMessage() );
 		}
@@ -572,28 +511,28 @@ public class SphinxClient
 	/**
 	 * Set float range filter.
 	 *
-	 * Only match those records where <code>attribute</code> column values
-	 * is beetwen <code>min</code> and <code>max</code> (including
-	 * <code>min</code> and <code>max</code>)
+	 * Only match those documents where <code>attribute</code> column value
+	 * is beetwen given min and max values (including themselves).
 	 *
 	 * @param attribute		attribute name to filter by
 	 * @param min			min attribute value
 	 * @param max			max attribute value
-	 * @param exclude		exclude-filter or include-filter flag
+	 * @param exclude		whether to exclude matching documents instead
 	 *
 	 * @throws SphinxException on invalid parameters
+	 * Set float range filter.
 	 */
 	public void SetFilterFloatRange ( String attribute, float min, float max, boolean exclude ) throws SphinxException
 	{
 		myAssert ( min<=max, "min must be less or equal to max" );
 		try
 		{
-			writeNetUTF8(_filters, attribute);
-			_filters.writeInt(SPH_FILTER_RANGE);
-			_filters.writeFloat(min);
-			_filters.writeFloat(max);
-			_filters.writeInt(exclude ? 1 : 0);
-		} catch (Exception e)
+			writeNetUTF8 ( _filters, attribute );
+			_filters.writeInt ( SPH_FILTER_RANGE );
+			_filters.writeFloat ( min );
+			_filters.writeFloat ( max );
+			_filters.writeInt ( exclude ? 1 : 0 );
+		} catch ( Exception e )
 		{
 			myAssert ( false, "IOException: " + e.getMessage() );
 		}
@@ -604,7 +543,7 @@ public class SphinxClient
 	 * Setup geographical anchor point.
 	 *
 	 * Required to use @geodist in filters and sorting.
-	 * Distance will be computed to this point
+	 * Distance will be computed to this point.
 	 *
 	 * @param latitudeAttr		the name of latitude attribute
 	 * @param longitudeAttr		the name of longitude attribute
@@ -624,40 +563,8 @@ public class SphinxClient
 		_longitude = longitude;
 	}
 
-	/**
-	 * Set grouping attribute and function.
-	 * <p/>
-	 * in grouping mode, all matches are assigned to different groups
-	 * based on grouping function value.
-	 * <p/>
-	 * each group keeps track of the total match count, and the best match
-	 * (in this group) according to current sorting function.
-	 * <p/>
-	 * the final result set contains one best match per group, with
-	 * grouping function value and matches count attached.
-	 * <p/>
-	 * result set could be sorted either by 1) grouping function value
-	 * in descending order (this is the default mode, when $sortbygroup
-	 * is set to true); or by 2) current sorting function (when $sortbygroup
-	 * is false).
-	 * <p/>
-	 * WARNING, when sorting by current function there might be less
-	 * matching groups reported than actually present. @count might also be
-	 * underestimated.
-	 * <p/>
-	 * for example, if sorting by relevance and grouping by "published"
-	 * attribute with SPH_GROUPBY_DAY function, then the result set will
-	 * contain one most relevant match per each day when there were any
-	 * matches published, with day number and per-day match count attached,
-	 * and sorted by day number in descending order (ie. recent days first).
-	 *
-	 * @param attribute grouping attribute name
-	 * @param func	func type (See predefined SPH_GROUPBY_* constants for details)
-	 * @param groupsort soft type ("@group desc" by default)
-	 *
-	 * @throws SphinxException on invalid parameters
-	 */
-	public void SetGroupBy(String attribute, int func, String groupsort) throws SphinxException
+	/** Set grouping attribute and function. */
+	public void SetGroupBy ( String attribute, int func, String groupsort ) throws SphinxException
 	{
 		myAssert (
 			func==SPH_GROUPBY_DAY ||
@@ -672,38 +579,20 @@ public class SphinxClient
 		_groupSort = groupsort;
 	}
 
-	/**
-	 * Set grouping attribute and function with default ("@group desc") groupsort
-	 *
-	 * @param attribute attribute to group by
-	 * @param func	groupping type
-	 *
-	 * @throws SphinxException on invalid parameters
-	 */
+	/** Set grouping attribute and function with default ("@group desc") groupsort (syntax sugar). */
 	public void SetGroupBy(String attribute, int func) throws SphinxException
 	{
 		SetGroupBy(attribute, func, "@group desc");
 	}
 
-	/**
-	 * set count-distinct attribute for group-by queries
-	 *
-	 * @param attribute group by attribute
-	 */
+	/** Set count-distinct attribute for group-by queries. */
 	public void SetGroupDistinct(String attribute)
 	{
 		_groupDistinct = attribute;
 	}
 
-	/**
-	 * set distributed retries count and delay
-	 *
-	 * @param count retry count
-	 * @param delay retry delay
-	 *
-	 * @throws SphinxException on invalid parameters
-	 */
-	public void SetRetries(int count, int delay) throws SphinxException
+	/** Set distributed retries count and delay. */
+	public void SetRetries ( int count, int delay ) throws SphinxException
 	{
 		myAssert ( count>=0, "count must not be negative" );
 		myAssert ( delay>=0, "delay must not be negative" );
@@ -711,21 +600,13 @@ public class SphinxClient
 		_retrydelay = delay;
 	}
 
-	/**
-	 * set distributed retries count with zero delay
-	 *
-	 * @param count retry count
-	 *
-	 * @throws SphinxException on invalid parameters
-	 */
-	public void SetRetries(int count) throws SphinxException
+	/** Set distributed retries count with default (zero) delay (syntax sugar). */
+	public void SetRetries ( int count ) throws SphinxException
 	{
-		SetRetries(count, 0);
+		SetRetries ( count, 0 );
 	}
 
-	/**
-	 * clear all filters (for multi-queries)
-	 */
+	/** Reset all currently set filters (for multi-queries). */
 	public void ResetFilters()
 	{
 		/* should we close them first? */
@@ -740,32 +621,23 @@ public class SphinxClient
 		_longitude = 0;
 	}
 
-	/**
-	 * connect to searchd server and run given search query against all indexes
-	 *
-	 * @param query string
-	 * @return {@link SphinxResult} result set or null on error
-	 *
-	 * @throws SphinxException on invalid parameters
-	 */
+	/** Connect to searchd server and run current search query against all indexes (syntax sugar). */
 	public SphinxResult Query(String query) throws SphinxException
 	{
 		return Query(query, "*");
 	}
 
 	/**
-	 * Connect to searchd server and run given search query.
+	 * Connect to searchd server and run current search query.
 	 *
-	 * @param query query string
-	 * @param index index name to query, can be "*" which means to query all indexes
-	 * (default for <code>Query(String query)</code>)
-	 * @return {@link SphinxResult} result set object, which contains retrieved
-	 * matches as well as some per-collection statistics (total found matches,
-	 * query time, per-word statistics, etc)
+	 * @param query		query string
+	 * @param index		index name(s) to query. May contain anything-separated
+	 *					list of index names, or "*" which means to query all indexes.
+	 * @return			{@link SphinxResult} object
 	 *
 	 * @throws SphinxException on invalid parameters
 	 */
-	public SphinxResult Query(String query, String index) throws SphinxException
+	public SphinxResult Query ( String query, String index ) throws SphinxException
 	{
 		myAssert ( _reqs==null || _reqs.size()==0, "AddQuery() and Query() can not be combined; use RunQueries() instead" );
 
@@ -786,7 +658,8 @@ public class SphinxClient
 		}
 	}
 
-	public synchronized int AddQuery(String query, String index) throws SphinxException
+	/** Add new query with current settings to current search request. */
+	public int AddQuery ( String query, String index ) throws SphinxException
 	{
 		ByteArrayOutputStream req = new ByteArrayOutputStream();
 
@@ -865,6 +738,7 @@ public class SphinxClient
 		return -1;
 	}
 
+	/** Run all previously added search queries. */
 	public SphinxResult[] RunQueries() throws SphinxException
 	{
 		if (_reqs == null || _reqs.size() < 1) {
@@ -956,20 +830,20 @@ public class SphinxClient
 				/* read match count */
 				int count = in.readInt();
 				int id64 = in.readInt();
-				res.matches = new SphinxDocInfo[count];
+				res.matches = new SphinxMatch[count];
 				for (int matchesNo = 0; matchesNo < count; matchesNo++) {
-					SphinxDocInfo docInfo;
+					SphinxMatch docInfo;
 					if (id64 != 0) {
 						int docHi = in.readInt();
 						int docLo = in.readInt();
 						long doc64 = docHi;
 						doc64 = doc64 << 32 + docLo;
 						int weight = in.readInt();
-						docInfo = new SphinxDocInfo(doc64, weight);
+						docInfo = new SphinxMatch(doc64, weight);
 					} else {
 						int docId = in.readInt();
 						int weight = in.readInt();
-						docInfo = new SphinxDocInfo(docId, weight);
+						docInfo = new SphinxMatch(docId, weight);
 					}
 
 					/* read matches */
@@ -979,24 +853,26 @@ public class SphinxClient
 						int type = res.attrTypes[attrNumber];
 
 						/* handle floats */
-						if (type == SPH_ATTR_FLOAT) {
-							float value = in.readFloat();
-							docInfo.setAttr(attrNumber, value);
+						if ( type==SPH_ATTR_FLOAT )
+						{
+							docInfo.attrValues.add ( attrNumber, new Float ( in.readFloat() ) );
 							continue;
 						}
 
 						/* handle everything else as unsigned ints */
 						int val = in.readInt();
-						if ((type & SPH_ATTR_MULTI) != 0) {
+						if ( ( type & SPH_ATTR_MULTI )!=0 )
+						{
 							int[] vals = new int[val];
-							for (int k = 0; k < val; k++) {
+							for ( int k=0; k<val; k++ )
 								vals[k] = in.readInt();
-							}
-							docInfo.setAttr(attrName, vals);
-						} else {
-							docInfo.setAttr(attrNumber, val);
+
+							docInfo.attrValues.add ( attrNumber, vals );
+
+						} else
+						{
+							docInfo.attrValues.add ( attrNumber, val );
 						}
-						docInfo.setAttr(attrNumber, val);
 					}
 					res.matches[matchesNo] = docInfo;
 				}
@@ -1031,22 +907,23 @@ public class SphinxClient
 	}
 
 	/**
-	 * connect to searchd server and generate exceprts from given documents.
+	 * Connect to searchd server and generate exceprts from given documents.
 	 *
-	 * @param docs is an array of strings which represent the documents' contents
-	 * @param index is a string specifiying the index which settings will be used for stemming, lexing and case folding
-	 * @param words is a string which contains the words to highlight
-	 * @param opts opts is a hash which contains additional optional highlighting parameters:
-	 * "before_match" - a string to insert before a set of matching words, default is "<b>";
-	 * "after_match" - a string to insert after a set of matching words, default is "<b>";
-	 * "chunk_separator" - a string to insert between excerpts chunks, default is " ... ";
-	 * "limit" - max excerpt size in symbols (codepoints), default is 256;
-	 * "around" - how much words to highlight around each match, default is 5
-	 * @return false on failure, an array of string excerpts on success
+	 * @param docs		an array of strings which represent the documents' contents
+	 * @param index		a string with the name of the index which settings will be used for stemming, lexing and case folding
+	 * @param words		a string which contains the query words to highlight
+	 * @param opts		a hash with additional optional highlighting parameters:
+	 *					<ul>
+	 *					<li><b>"before_match"</b>, a string to insert before a set of matching words (default is "&lt;b*gt;");
+	 *					<li><b>"after_match"</b>, a string to insert after a set of matching words (default is "&lt;/b*gt;");
+	 *					<li><b>"chunk_separator"</b>, a string to insert between excerpts chunks (default is "...");
+	 *					<li><b>"limit"</b>, max excerpt size in codepoints (default is 256);
+	 *					<li><b>"around"</b>, how much words to highlight around each match (default is 5).
+	 * @return			null on failure, an array of string excerpts on success
 	 *
 	 * @throws SphinxException on invalid parameters
 	 */
-	public String[] BuildExcerpts(String[] docs, String index, String words, Map opts) throws SphinxException
+	public String[] BuildExcerpts ( String[] docs, String index, String words, Map opts ) throws SphinxException
 	{
 		myAssert(docs != null && docs.length > 0, "BuildExcerpts: Have no documents to process");
 		myAssert(index != null && index.length() > 0, "BuildExcerpts: Have no index to process documents");
@@ -1125,9 +1002,7 @@ public class SphinxClient
 		}
 	}
 
-	/**
-	 * Internal sanity check syntax sugar.
-	 */
+	/** Internal sanity check. */
 	private void myAssert ( boolean condition, String err ) throws SphinxException
 	{
 		if ( !condition )
@@ -1137,33 +1012,18 @@ public class SphinxClient
 		}
 	}
 
-	/**
-	 * java to sphinx String protocol hack
-	 * Adds lead 2 zero bytes to stream before string length to make length 4 bytes
-	 * as expected by search server
-	 *
-	 * @param ostream output stream to write <code>String</code> to
-	 * @param str	 <code>String</code> to send to sphinx server
-	 */
+	/** String IO helper (internal method). */
 	private static void writeNetUTF8(DataOutputStream ostream, String str) throws IOException
 	{
 		ostream.writeShort(0);
 		ostream.writeUTF(str);
 	}
 
-	/**
-	 * sphinx to java String protocol hack
-	 * Reads first 2 lead bytes from stream before string length to make length
-	 * 2 bytes as expected by Java modified UTF8 (see also {@link DataInputStream})
-	 *
-	 * @param istream output stream to write <code>String</code> to
-	 * @return str <code>String</code> sent from sphinx server
-	 */
+	/** String IO helper (internal method). */
 	private static String readNetUTF8(DataInputStream istream) throws IOException
 	{
-		int dummy = istream.readUnsignedShort(); /* searchd emits dwords, Java expects words */
-		String value = istream.readUTF();
-		return value;
+		istream.readUnsignedShort (); /* searchd emits dword lengths, but Java expects words; lets just skip first 2 bytes */
+		return istream.readUTF ();
 	}
 }
 

+ 0 - 89
api/java/SphinxDocInfo.java

@@ -1,89 +0,0 @@
-package org.sphx.api;
-
-import java.util.*;
-
-/**
- * Document information helper class.
- * Can be found in SphinxResult.matches
- */
-public class SphinxDocInfo
-{
-	private long docId;
-	private int weight;
-	private ArrayList attrValues = null;
-
-	/**
-	 * Create document info using document id and its weight
-	 *
-	 * @param docId
-	 * @param weight
-	 */
-	public SphinxDocInfo(long docId, int weight)
-	{
-		this.attrValues = new ArrayList();
-		this.docId = docId;
-		this.weight = weight;
-	}
-
-	/**
-	 * Get attribute set for this document.
-	 *
-	 * @return set of doc attributes
-	 */
-	public ArrayList getAttrValues()
-	{
-		return attrValues;
-	}
-
-	public long getDocId()
-	{
-		return docId;
-	}
-
-	public int getWeight()
-	{
-		return weight;
-	}
-
-	/**
-	 * Get attribute value for given attribute name for this document
-	 *
-	 * @return attribute value for this document
-	 */
-	public int getAttr(int no)
-	{
-		Integer value = (Integer) this.attrValues.get(no);
-		return value.intValue();
-	}
-
-	/**
-	 * Set attribute value for given attribute name for this document
-	 *
-	 * @param attrName attribute name
-	 * @param value	value for this document
-	 */
-	public void setAttr(String attrName, Object value)
-	{
-		this.attrValues.add(value);
-	}
-
-	/**
-	 * Set integer attribute value for given attribute name for this document
-	 * @param value	value for this document
-	 */
-	public void setAttr(int no, int value)
-	{
-		Integer iBox = new Integer(value);
-		this.attrValues.add(no, iBox);
-	}
-
-	/**
-	 * Set integer attribute value for given attribute name for this document
-	 * @param value	value for this document
-	 */
-	public void setAttr(int no, float value)
-	{
-		Float iBox = new Float(value);
-		this.attrValues.add(no, iBox);
-	}
-}

+ 13 - 20
api/java/SphinxException.java

@@ -1,31 +1,24 @@
+/*
+ * $Id$
+ */
+
 package org.sphx.api;
 
-/**
- * SphinxException used by non-canonical functions.
- */
+/** Exception thrown on attempts to pass invalid arguments to Sphinx API methods. */
 public class SphinxException extends Exception
 {
-
-	/**
-	 * Constructs a new Sphinx exception with <code>null</code> as its detail message.
-	 * The cause is not initialized, and may subsequently be initialized by a
-	 * call to {@link #initCause}.
-	 */
+	/** Trivial constructor. */
 	public SphinxException()
 	{
 	}
 
-
-	/**
-	 * Constructs a new Sphinx exception with the specified detail message. The
-	 * cause is not initialized, and may subsequently be initialized by
-	 * a call to {@link #initCause}.
-	 *
-	 * @param message the detail message. The detail message is saved for
-	 * later retrieval by the {@link #getMessage()} method.
-	 */
-	public SphinxException(String message)
+	/** Constructor from error message string. */
+	public SphinxException ( String message )
 	{
-		super(message);
+		super ( message );
 	}
 }
+
+/*
+ * $Id$
+ */

+ 35 - 0
api/java/SphinxMatch.java

@@ -0,0 +1,35 @@
+/*
+ * $Id$
+ */
+
+package org.sphx.api;
+
+import java.util.*;
+
+/**
+ * Matched document information, as in search result.
+ */
+public class SphinxMatch
+{
+	/** Matched document ID. */
+	public long		docId;
+
+	/** Matched document weight. */
+	public int			weight;
+
+	/** Matched document attribute values. */
+	public ArrayList	attrValues;
+
+
+	/** Trivial constructor. */
+	public SphinxMatch ( long docId, int weight )
+	{
+		this.docId = docId;
+		this.weight = weight;
+		this.attrValues = new ArrayList();
+	}
+}
+
+/*
+ * $Id$
+ */

+ 51 - 104
api/java/SphinxResult.java

@@ -1,128 +1,75 @@
+/*
+ * $Id$
+ */
+
 package org.sphx.api;
 
 /**
- * Sphinx result set class which store the following information on success:
- * "matches"
- * hash which maps found document_id to SphinxDocInfo( "weight", "group" ) hash
- * "total"
- * total amount of matches retrieved (upto SPH_MAX_MATCHES, see sphinx.h)
- * "totalFound"
- * total amount of matching documents in index
- * "time"
- * search time
- * "words"
- * hash which maps query terms (stemmed!) to ( "docs", "hits" ) hash
+ * Search result set.
  *
- * Disclamer. Well. This is mostly C++ vision on how should java code be.
- * to find "native" java API visit FIXME
+ * Includes retrieved matches array, status code and error/warning messages,
+ * query stats, and per-word stats.
  */
 public class SphinxResult
 {
-	/**
-	 * Fields returned by sphinx
-	 */
-	public String[] fields;
-	/**
-	 * attribute map
-	 */
-	public String[] attrNames;
-	/**
-	 * attribute attrTypes
-	 */
-	public int[] attrTypes;
-	/**
-	 * DocInfo matches
-	 */
-	public SphinxDocInfo[] matches;
-	/**
-	 * total documents in result set
-	 */
-	public int total;
-	/**
-	 * total documents found
-	 */
-	public int totalFound;
-	/**
-	 * time took
-	 */
-	public float time;
-	/**
-	 * words SphinxWordInfo)
-	 */
-	public SphinxWordInfo[] words;
-	/**
-	 * warning for this request
-	 */
-	public String warning = null;
-	/**
-	 * error for this request
-	 */
-	public String error = null;
-	/**
-	 * status returned by server
-	 */
-	private int status = -1;
-
-
-	/**
-	 * Read result status
-	 *
-	 * @return status code
-	 */
-	public int getStatus()
-	{
-		return status;
-	}
+	/** Full-text field namess. */
+	public String[]			fields;
 
-	/**
-	 * Status setter. Visible only to org.sphx.api package
-	 *
-	 * @param status status to set
-	 */
-	void setStatus(int status)
-	{
-		this.status = status;
-	}
+	/** Attribute names. */
+	public String[]			attrNames;
+
+	/** Attribute types (refer to SPH_ATTR_xxx constants in SphinxClient). */
+	public int[]			attrTypes;
+
+	/** Retrieved matches. */
+	public SphinxMatch[]	matches;
+
+	/** Total matches in this result set. */
+	public int				total;
+
+	/** Total matches found in the index(es). */
+	public int				totalFound;
+
+	/** Elapsed time (as reported by searchd), in seconds. */
+	public float			time;
 
-	/**
-	 * creates an empty result set
-	 */
+	/** Per-word statistics. */
+	public SphinxWordInfo[]	words;
+
+	/** Warning message, if any. */
+	public String			warning = null;
+
+	/** Error message, if any. */
+	public String			error = null;
+
+
+	/** Query status (refer to SEARCHD_xxx constants in SphinxClient). */
+	private int				status = -1;
+
+
+	/** Trivial constructor, initializes an empty result set. */
 	public SphinxResult()
 	{
 		this.attrNames = new String[0];
-		this.matches = new SphinxDocInfo[0];;
+		this.matches = new SphinxMatch[0];;
 		this.words = new SphinxWordInfo[0];
 		this.fields = new String[0];
 		this.attrTypes = new int[0];
 	}
 
-	/**
-	 * get all matches from the result set
-	 * @return hash document_id to SphinxDocInfo( "weight", "group" )
-	 */
-	public SphinxDocInfo[] getMatches()
-	{
-		return matches;
-	}
-
-	/**
-	 * Get total amount of matches retrieved
-	 *
-	 * @return int total
-	 */
-	public int getTotal()
+	/** Get query status. */
+	public int getStatus()
 	{
-		return total;
+		return status;
 	}
 
-	/**
-	 * Get total amount of matching documents in index
-	 *
-	 * @return amount of matching documents
-	 */
-	public int getTotalFound()
+	/** Set query status (accessible from API package only). */
+	void setStatus ( int status )
 	{
-		return totalFound;
+		this.status = status;
 	}
 }
 
+/*
+ * $Id$
+ */

+ 19 - 8
api/java/SphinxWordInfo.java

@@ -1,19 +1,30 @@
+/*
+ * $Id$
+ */
+
 package org.sphx.api;
 
-/**
- * Sphinx result word info.
- * Can be found in SphinxResult.words Map
- */
+/** Per-word statistics class. */
 public class SphinxWordInfo
 {
-	public String word;
-	public int docs;
-	public int hits;
+	/** Word form as returned from search daemon, stemmed or otherwise postprocessed. */
+	public String	word;
+
+	/** Total amount of matching documents in collection. */
+	public int		docs;
 
-	public SphinxWordInfo(String word, int docs, int hits)
+	/** Total amount of hits (occurences) in collection. */
+	public int		hits;
+
+	/** Trivial constructor. */
+	public SphinxWordInfo ( String word, int docs, int hits )
 	{
 		this.word = word;
 		this.docs = docs;
 		this.hits = hits;
 	}
 }
+
+/*
+ * $Id$
+ */

+ 97 - 79
api/java/test.java

@@ -1,3 +1,7 @@
+/*
+ * $Id$
+ */
+
 package org.sphx.api;
 
 import java.util.*;
@@ -7,67 +11,62 @@ import java.util.*;
  */
 public class test
 {
-	private static final int RESULT_LIMIT = 10;
-	private static final int MAX_RESULTS = 1000;
+	private static final int RESULT_LIMIT	= 20;
+	private static final int MAX_RESULTS	= 1000;
 
-	public static void main(String[] argv) throws SphinxException
+	public static void main ( String[] argv ) throws SphinxException
 	{
-		if (argv == null || argv.length < 2) {
-			System.out.println("usage: test [-a] <word [word [word [...]]]> [-g <group>] [-p <port>] [-h <host>] [-i <index>] [-e] [-b]");
-			System.out.println("or: test [-any] <word [word [word [...]]]> [--group <group>] [--port <port>] [--host <host>] [--index <index>] [--extended] [--boolean]\n");
+		if ( argv==null || argv.length<2 )
+		{
+			System.out.println ( "usage: test [-a] <word [word [word [...]]]> [-g <group>] [-p <port>] [-h <host>] [-i <index>] [-e] [-b]" );
+			System.out.println ( "or: test [-any] <word [word [word [...]]]> [--group <group>] [--port <port>] [--host <host>] [--index <index>] [--extended] [--boolean]\n" );
 		}
 
 		StringBuffer q = new StringBuffer();
 		String host = "localhost";
+		int port = 3312;
 		int mode = SphinxClient.SPH_MATCH_ALL;
 		Set groups = new LinkedHashSet();
-		int port = 3312;
 		String index = "*";
 		int offset = 0;
 
 		/* parse arguments */
-		if (argv != null) {
-			for (int i = 0; i < argv.length; i++) {
-				String arg = argv[i];
-				if ("-a".equalsIgnoreCase(arg) || "--any".equalsIgnoreCase(arg)) {
-					mode = SphinxClient.SPH_MATCH_ANY;
-				} else if ("-b".equalsIgnoreCase(arg) || "--boolean".equalsIgnoreCase(arg)) {
-					mode = SphinxClient.SPH_MATCH_BOOLEAN;
-				} else if ("-e".equalsIgnoreCase(arg) || "--extended".equalsIgnoreCase(arg)) {
-					mode = SphinxClient.SPH_MATCH_EXTENDED;
-				} else if ("-g".equalsIgnoreCase(arg) || "--group".equalsIgnoreCase(arg)) {
-					groups.add(argv[++i]);
-				} else if ("-p".equalsIgnoreCase(arg) || "--port".equalsIgnoreCase(arg)) {
-					port = Integer.parseInt(argv[++i]);
-				} else if ("-h".equalsIgnoreCase(arg) || "--host".equalsIgnoreCase(arg)) {
-					host = argv[++i];
-				} else if ("-o".equalsIgnoreCase(arg) || "--offsset".equalsIgnoreCase(arg)) {
-					offset = Integer.parseInt(argv[++i]);
-				} else if ("-i".equalsIgnoreCase(arg) || "--index".equalsIgnoreCase(arg)) {
-					index = argv[++i];
-				} else {
-					q.append(argv[i]).append(" ");
-				}
-			}
+		if ( argv!=null)
+			for ( int i=0; i<argv.length; i++ )
+		{
+			String arg = argv[i];
+			if ( "-a".equals(arg) || "--any".equals(arg) )				mode = SphinxClient.SPH_MATCH_ANY;
+			else if ( "-b".equals(arg) || "--boolean".equals(arg) )		mode = SphinxClient.SPH_MATCH_BOOLEAN;
+			else if ( "-e".equals(arg) || "--extended".equals(arg) )	mode = SphinxClient.SPH_MATCH_EXTENDED;
+			else if ( "-g".equals(arg) || "--group".equals(arg) )		groups.add ( argv[++i] );
+			else if ( "-p".equals(arg) || "--port".equals(arg) )		port = Integer.parseInt ( argv[++i] );
+			else if ( "-h".equals(arg) || "--host".equals(arg) )		host = argv[++i];
+			else if ( "-o".equals(arg) || "--offsset".equals(arg) )		offset = Integer.parseInt(argv[++i]);
+			else if ( "-i".equals(arg) || "--index".equals(arg) )		index = argv[++i];
+			else q.append ( argv[i] ).append ( " " );
 		}
 
 		SphinxClient cl = new SphinxClient();
-		cl.SetServer(host, port);
-		cl.SetWeights(new int[]{100, 1});
-		cl.SetMatchMode(mode);
-		cl.SetLimits(offset, RESULT_LIMIT, MAX_RESULTS);
+		cl.SetServer ( host, port );
+		cl.SetWeights ( new int[] { 100, 1 } );
+		cl.SetMatchMode ( mode );
+		cl.SetLimits ( offset, RESULT_LIMIT, MAX_RESULTS );
 
 		/* convert groups to int[] */
-		if (groups.size() > 0) {
+		if ( groups.size()>0 )
+		{
 			int[] groupList = new int[groups.size()];
 			String group = null;
 			int i = 0;
-			try {
-				for (Iterator e = groups.iterator(); e.hasNext(); i++) {
+			try
+			{
+				for (Iterator e = groups.iterator(); e.hasNext(); i++)
+				{
 					group = (String) e.next();
 					groupList[i] = Integer.parseInt(group);
 				}
-			} catch (Exception ex) {
+			} catch (Exception ex)
+			{
 				System.out.println("Groups must be integer. Failed to convert group " + group);
 				return;
 			}
@@ -75,60 +74,79 @@ public class test
 		}
 
 		SphinxResult res = cl.Query(q.toString(), index);
-		if (res == null || (cl.GetLastError() != null && cl.GetLastError().length() > 0)) {
+		if (res == null || (cl.GetLastError() != null && cl.GetLastError().length() > 0))
+		{
 			System.err.println("Error: " + cl.GetLastError());
 			System.exit(1);
 		}
 
 		/* print me out */
-		System.out.println("Query " + q + " retrieved " + res.total + " of " + res.totalFound + " matches in " + res.time + " sec.");
-		System.out.println("Query stats:");
-		for (int i = 0; i < res.words.length; i++) {
+		System.out.println ( "Query '" + q + "' retrieved " + res.total + " of " + res.totalFound + " matches in " + res.time + " sec." );
+		System.out.println ( "Query stats:" );
+		for ( int i=0; i<res.words.length; i++ )
+		{
 			SphinxWordInfo wordInfo = res.words[i];
-			System.out.println(wordInfo.word + " found " + wordInfo.hits + " times in " + wordInfo.docs + " documents");
+			System.out.println ( "\t'" + wordInfo.word + "' found " + wordInfo.hits + " times in " + wordInfo.docs + " documents" );
 		}
 
-		System.out.println("Matches:");
-		for (int i = 0; i < res.matches.length; i++) {
-			SphinxDocInfo info = res.matches[i];
-			System.out.print("DocId=" + info.getDocId() + ", weight=" + info.getWeight());
-			System.out.print(", attrNames: ");
-			ArrayList attrs = info.getAttrValues();
+		System.out.println ( "\nMatches:" );
+		for ( int i=0; i<res.matches.length; i++ )
+		{
+			SphinxMatch info = res.matches[i];
+			System.out.print ( (i+1) + ". id=" + info.docId + ", weight=" + info.weight );
+
+			if ( res.attrNames==null || res.attrTypes==null )
+				continue;
+
+			for ( int a=0; a<res.attrNames.length; a++ )
+			{
+				System.out.print ( ", " + res.attrNames[a] + "=" );
 
-			if (res.attrNames != null && res.attrTypes != null)
-			for (int attrNo = 0; attrNo < res.attrNames.length; attrNo++) {
-				switch (res.attrTypes[attrNo])
+				if ( ( res.attrTypes[a] & SphinxClient.SPH_ATTR_MULTI )!=0 )
 				{
-					case SphinxClient.SPH_ATTR_INTEGER:
-						Integer attrI = (Integer) attrs.get(attrNo);
-						System.out.print(res.attrNames[attrNo] + "=" + attrI.intValue() + " ");
-						break;
-					case SphinxClient.SPH_ATTR_FLOAT:
-						Float attrF = (Float) attrs.get(attrNo);
-						System.out.print(res.attrNames[attrNo] + "=" + attrF.floatValue() + " ");
-						break;
-					case SphinxClient.SPH_ATTR_MULTI:
-						int[] attrM = (int[]) attrs.get(attrNo);
-						if (attrM != null)
-						for (int j = 0; j < attrM.length; j++)
-						{
-							System.out.print(res.attrNames[attrNo] + "[" + j + "]=" + attrM[j] + " ");
-						}
-						break;
-					case SphinxClient.SPH_ATTR_ORDINAL:
-						String attrS = (String) attrs.get(attrNo);
-						System.out.print(res.attrNames[attrNo] + "=" + attrS + " ");
-						break;
-					case SphinxClient.SPH_ATTR_TIMESTAMP:
-						Integer attrT = (Integer) attrs.get(attrNo);
-						Date date = new Date(attrT.longValue());
-						System.out.print(res.attrNames[attrNo] + "=" + date.toString() + " ");
-						break;
-					default:
-						System.out.print(res.attrNames[attrNo] + " type id = " + res.attrTypes[attrNo]);
+					System.out.print ( "(" );
+					int[] attrM = (int[]) info.attrValues.get(a);
+					if ( attrM!=null )
+						for ( int j=0; j<attrM.length; j++ )
+					{
+						if ( j!=0 )
+							System.out.print ( "," );
+						System.out.print ( attrM[j] );
+					}
+					System.out.print ( ")" );
+
+				} else
+				{
+					switch ( res.attrTypes[a] )
+					{
+						case SphinxClient.SPH_ATTR_INTEGER:
+						case SphinxClient.SPH_ATTR_ORDINAL:
+							Integer attrI = (Integer) info.attrValues.get(a);
+							System.out.print ( attrI.intValue() );
+							break;
+
+						case SphinxClient.SPH_ATTR_FLOAT:
+							Float attrF = (Float) info.attrValues.get(a);
+							System.out.print ( attrF.floatValue() );
+							break;
+
+						case SphinxClient.SPH_ATTR_TIMESTAMP:
+							Integer attrT = (Integer) info.attrValues.get(a);
+							Date date = new Date ( attrT.longValue()*1000 );
+							System.out.print ( date.toString() );
+							break;
+
+						default:
+							System.out.print ( "(unknown-attr-type=" + res.attrTypes[a] + ")" );
+					}
 				}
 			}
+
 			System.out.println();
 		}
 	}
 }
+
+/*
+ * $Id$
+ */