/*------------------------------------------------------------------------------ * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team * * Distributable under the terms of either the Apache License (Version 2.0) or * the GNU Lesser General Public License, as specified in the COPYING file. ------------------------------------------------------------------------------*/ #ifndef _lucene_search_FuzzyQuery_ #define _lucene_search_FuzzyQuery_ #include "MultiTermQuery.h" #include "FilteredTermEnum.h" CL_CLASS_DEF(index,Term) CL_NS_DEF(search) /** Implements the fuzzy search query. The similiarity measurement * is based on the Levenshtein (edit distance) algorithm. */ class CLUCENE_EXPORT FuzzyQuery : public MultiTermQuery { private: float_t minimumSimilarity; size_t prefixLength; protected: FuzzyQuery(const FuzzyQuery& clone); public: static float_t defaultMinSimilarity; static int32_t defaultPrefixLength; /** * Create a new FuzzyQuery that will match terms with a similarity * of at least minimumSimilarity to term. * If a prefixLength > 0 is specified, a common prefix * of that length is also required. * * @param term the term to search for * @param minimumSimilarity a value between 0 and 1 to set the required similarity * between the query term and the matching terms. For example, for a * minimumSimilarity of 0.5 a term of the same length * as the query term is considered similar to the query term if the edit distance * between both terms is less than length(term)*0.5 * @param prefixLength length of common (non-fuzzy) prefix * @throws IllegalArgumentException if minimumSimilarity is > 1 or < 0 * or if prefixLength < 0 or > term.text().length(). */ FuzzyQuery(CL_NS(index)::Term* term, float_t minimumSimilarity=-1, size_t prefixLength=0); virtual ~FuzzyQuery(); /** * Returns the minimum similarity that is required for this query to match. * @return float value between 0.0 and 1.0 */ float_t getMinSimilarity() const; /** * Returns the prefix length, i.e. the number of characters at the start * of a term that must be identical (not fuzzy) to the query term if the query * is to match that term. */ size_t getPrefixLength() const; Query* rewrite(CL_NS(index)::IndexReader* reader); TCHAR* toString(const TCHAR* field) const; //Returns the name "FuzzyQuery" static const char* getClassName(); const char* getObjectName() const; Query* clone() const; bool equals(Query * other) const; size_t hashCode() const; protected: FilteredTermEnum* getEnum(CL_NS(index)::IndexReader* reader); }; /** Subclass of FilteredTermEnum for enumerating all terms that are similiar * to the specified filter term. * *

Term enumerations are always ordered by Term.compareTo(). Each term in * the enumeration is greater than all that precede it. */ class CLUCENE_EXPORT FuzzyTermEnum: public FilteredTermEnum { private: /* Allows us save time required to create a new array * everytime similarity is called. */ int32_t* d; size_t dLen; //float_t distance; float_t _similarity; bool _endEnum; CL_NS(index)::Term* searchTerm; //String field; TCHAR* text; size_t textLen; TCHAR* prefix; size_t prefixLength; float_t minimumSimilarity; double scale_factor; int32_t maxDistances[LUCENE_TYPICAL_LONGEST_WORD_IN_INDEX]; /****************************** * Compute Levenshtein distance ******************************/ /** *

Similarity returns a number that is 1.0f or less (including negative numbers) * based on how similar the Term is compared to a target term. It returns * exactly 0.0f when *

	*    editDistance < maximumEditDistance
* Otherwise it returns: *
	*    1 - (editDistance / length)
* where length is the length of the shortest term (text or target) including a * prefix that are identical and editDistance is the Levenshtein distance for * the two words.

* *

Embedded within this algorithm is a fail-fast Levenshtein distance * algorithm. The fail-fast algorithm differs from the standard Levenshtein * distance algorithm in that it is aborted if it is discovered that the * mimimum distance between the words is greater than some threshold. * *

To calculate the maximum distance threshold we use the following formula: *

	*     (1 - minimumSimilarity) * length
* where length is the shortest term including any prefix that is not part of the * similarity comparision. This formula was derived by solving for what maximum value * of distance returns false for the following statements: *
	*   similarity = 1 - ((float)distance / (float) (prefixLength + Math.min(textlen, targetlen)));
	*   return (similarity > minimumSimilarity);
* where distance is the Levenshtein distance for the two words. *

*

Levenshtein distance (also known as edit distance) is a measure of similiarity * between two strings where the distance is measured as the number of character * deletions, insertions or substitutions required to transform one string to * the other string. * @param target the target word or phrase * @return the similarity, 0.0 or less indicates that it matches less than the required * threshold and 1.0 indicates that the text and target are identical */ float_t similarity(const TCHAR* target, const size_t targetLen); /** * The max Distance is the maximum Levenshtein distance for the text * compared to some other value that results in score that is * better than the minimum similarity. * @param m the length of the "other value" * @return the maximum levenshtein distance that we care about */ int32_t getMaxDistance(const size_t m); void initializeMaxDistances(); int32_t calculateMaxDistance(const size_t m) const; protected: /** * The termCompare method in FuzzyTermEnum uses Levenshtein distance to * calculate the distance between the given term and the comparing term. */ bool termCompare(CL_NS(index)::Term* term) ; /** Returns the fact if the current term in the enumeration has reached the end */ bool endEnum(); public: /** * Constructor for enumeration of all terms from specified reader which share a prefix of * length prefixLength with term and which have a fuzzy similarity > * minSimilarity. *

* After calling the constructor the enumeration is already pointing to the first * valid term if such a term exists. * * @param reader Delivers terms. * @param term Pattern term. * @param minSimilarity Minimum required similarity for terms from the reader. Default value is 0.5f. * @param prefixLength Length of required common prefix. Default value is 0. * @throws IOException */ FuzzyTermEnum(CL_NS(index)::IndexReader* reader, CL_NS(index)::Term* term, float_t minSimilarity=FuzzyQuery::defaultMinSimilarity, size_t prefixLength=0); virtual ~FuzzyTermEnum(); /** Close the enumeration */ void close(); /** Returns the difference between the distance and the fuzzy threshold * multiplied by the scale factor */ float_t difference(); const char* getObjectName() const; static const char* getClassName(); }; CL_NS_END #endif