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:
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user