From Bruno Garcia: Add a mode for FullText to search for rows that match all the words in a query rather than any of them.

This commit is contained in:
Par Winzell
2011-08-24 15:04:43 +00:00
parent 3c1e6f7538
commit 710d2ffaf2
3 changed files with 51 additions and 13 deletions
@@ -10,6 +10,8 @@ import java.sql.SQLException;
import java.util.Map;
import java.util.Set;
import com.samskivert.util.StringUtil;
import com.samskivert.depot.PersistentRecord;
import com.samskivert.depot.annotation.FullTextIndex;
import com.samskivert.depot.expression.ColumnExp;
@@ -152,7 +154,7 @@ public class MySQLBuilder
new ColumnExp<Object>(pClass, fields[ii]).accept(this);
}
_builder.append(") against (");
bindValue(fullText.getQuery());
bindValue(massageFTQuery(fullText));
_builder.append(" in boolean mode)");
}
@@ -162,6 +164,19 @@ public class MySQLBuilder
}
}
protected static String massageFTQuery (FullText fullText)
{
// Split the query into words and remove punctuation
String[] searchTerms = fullText.getQuery().toLowerCase().trim().split("\\W+");
if (fullText.isMatchAll()) {
// Prepend every search term with a plus for ANDing
return '+' + StringUtil.join(searchTerms, " +");
} else {
// Use the default OR matching
return StringUtil.join(searchTerms, " ");
}
}
public MySQLBuilder (DepotTypes types)
{
super(types);
@@ -15,7 +15,6 @@ import java.util.Set;
import com.samskivert.jdbc.DatabaseLiaison;
import com.samskivert.jdbc.LiaisonRegistry;
import com.samskivert.util.ArrayUtil;
import com.samskivert.util.StringUtil;
import com.samskivert.depot.Exps;
@@ -259,18 +258,17 @@ public class PostgreSQLBuilder
return field.getType().equals(Long.TYPE) ? "BIGSERIAL" : "SERIAL";
}
protected static String massageFTQuery (FullText match)
protected static String massageFTQuery (FullText fullText)
{
// The tsearch2 engine takes queries on the form
// (foo&bar)|goop
// so in this first simple implementation, we just take the user query, chop it into
// words by space/punctuation and 'or' those together like so:
// 'ho! who goes there?' -> 'ho|who|goes|there'
String[] searchTerms = match.getQuery().toLowerCase().split("\\W+");
if (searchTerms.length > 0 && searchTerms[0].length() == 0) {
searchTerms = ArrayUtil.splice(searchTerms, 0, 1);
}
return StringUtil.join(searchTerms, "|");
// so in this implementation, we take the user query, chop it into words by and combine
// those together depending on the value of isMatchAll(), like so:
// 'ho! who goes there?' -> 'ho|who|goes|there' OR 'ho&who&goes&there'
//
String[] searchTerms = fullText.getQuery().toLowerCase().trim().split("\\W+");
String operator = fullText.isMatchAll() ? "&" : "|";
return StringUtil.join(searchTerms, operator);
}
// Translate the mildly abstracted full-text parser/dictionary configuration support
@@ -7,6 +7,7 @@ package com.samskivert.depot.operator;
import java.util.Collection;
import com.samskivert.depot.PersistentRecord;
import com.samskivert.depot.annotation.FullTextIndex;
import com.samskivert.depot.expression.FluentExp;
import com.samskivert.depot.impl.FragmentVisitor;
@@ -66,11 +67,29 @@ public class FullText
}
}
public FullText (Class<? extends PersistentRecord> pClass, String name, String query)
/**
* @param pClass The persistent record the full-text query is defined on.
* @param name The name of the corresponding {@link FullTextIndex}.
* @param query What to actually search for; this can be unprocessed natural language
* @param matchAll If true, all words in the query must be present in matches.
*/
public FullText (
Class<? extends PersistentRecord> pClass, String name, String query, boolean matchAll)
{
_pClass = pClass;
_name = name;
_query = query;
_matchAll = matchAll;
}
/**
* @param pClass The persistent record the full-text query is defined on.
* @param name The name of the corresponding {@link FullTextIndex}.
* @param query What to actually search for; this can be unprocessed natural language
*/
public FullText (Class<? extends PersistentRecord> pClass, String name, String query)
{
this(pClass, name, query, false);
}
public Match match ()
@@ -98,12 +117,18 @@ public class FullText
return _query;
}
public boolean isMatchAll ()
{
return _matchAll;
}
protected String toString (String subType)
{
return "FullText." + subType + "(" + _name + "=" + _query + ")";
return "FullText." + subType + "(" + _name + "=" + _query + ", " + _matchAll + ")";
}
protected Class<? extends PersistentRecord> _pClass;
protected String _name;
protected String _query;
protected boolean _matchAll;
}