Fix bug #12910134 Implement Search into the Settings App

- optimize MATCH query. Basically instead of doing 3 UNIONs,
we are building a more clever MATCH query that can search on
data_title OR data_summary OR data_keywords.
- the consequence is that the generated SQL should be way more
efficient to process and should also get the results faster.
- last, as the generated SQL is shorter, it will be easier to
understand and debug for Humans :-)

Change-Id: I0f71740cae86b8c95ed88f9a5d13b8b4c860b1a9
This commit is contained in:
Fabrice Di Meglio
2014-03-06 14:17:48 -08:00
parent 835c5e4ef9
commit 0d4005a1c7

View File

@@ -66,6 +66,12 @@ public class Index {
IndexColumns.ICON IndexColumns.ICON
}; };
private static final String[] MATCH_COLUMNS = {
IndexColumns.DATA_TITLE,
IndexColumns.DATA_SUMMARY,
IndexColumns.DATA_KEYWORDS
};
private static final String EMPTY = ""; private static final String EMPTY = "";
private static final String NON_BREAKING_HYPHEN = "\u2011"; private static final String NON_BREAKING_HYPHEN = "\u2011";
private static final String HYPHEN = "-"; private static final String HYPHEN = "-";
@@ -96,22 +102,20 @@ public class Index {
} }
public Cursor search(String query) { public Cursor search(String query) {
return getReadableDatabase().rawQuery(buildSQL(query), null); final String sql = buildSQL(query);
Log.d(LOG_TAG, "Query: " + sql);
return getReadableDatabase().rawQuery(sql, null);
} }
private String buildSQL(String query) { private String buildSQL(String query) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append(buildSQLForColumn(query, IndexColumns.DATA_TITLE)); sb.append(buildSQLForColumn(query, MATCH_COLUMNS));
sb.append(" UNION ");
sb.append(buildSQLForColumn(query, IndexColumns.DATA_SUMMARY));
sb.append(" UNION ");
sb.append(buildSQLForColumn(query, IndexColumns.DATA_KEYWORDS));
sb.append(" ORDER BY "); sb.append(" ORDER BY ");
sb.append(IndexColumns.DATA_RANK); sb.append(IndexColumns.DATA_RANK);
return sb.toString(); return sb.toString();
} }
private String buildSQLForColumn(String query, String columnName) { private String buildSQLForColumn(String query, String[] columnNames) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append("SELECT "); sb.append("SELECT ");
for (int n = 0; n < SELECT_COLUMNS.length; n++) { for (int n = 0; n < SELECT_COLUMNS.length; n++) {
@@ -123,15 +127,15 @@ public class Index {
sb.append(" FROM "); sb.append(" FROM ");
sb.append(Tables.TABLE_PREFS_INDEX); sb.append(Tables.TABLE_PREFS_INDEX);
sb.append(" WHERE "); sb.append(" WHERE ");
sb.append(buildWhereStringForColumn(query, columnName)); sb.append(buildWhereStringForColumns(query, columnNames));
return sb.toString(); return sb.toString();
} }
private String buildWhereStringForColumn(String query, String columnName) { private String buildWhereStringForColumns(String query, String[] columnNames) {
final StringBuilder sb = new StringBuilder(columnName); final StringBuilder sb = new StringBuilder(Tables.TABLE_PREFS_INDEX);
sb.append(" MATCH "); sb.append(" MATCH ");
DatabaseUtils.appendEscapedSQLString(sb, query + "*"); DatabaseUtils.appendEscapedSQLString(sb, buildMatchStringForColumns(query, columnNames));
sb.append(" AND "); sb.append(" AND ");
sb.append(IndexColumns.LOCALE); sb.append(IndexColumns.LOCALE);
sb.append(" = "); sb.append(" = ");
@@ -139,6 +143,21 @@ public class Index {
return sb.toString(); return sb.toString();
} }
private String buildMatchStringForColumns(String query, String[] columnNames) {
final String value = query + "*";
StringBuilder sb = new StringBuilder();
final int count = columnNames.length;
for (int n = 0; n < count; n++) {
sb.append(columnNames[n]);
sb.append(":");
sb.append(value);
if (n < count - 1) {
sb.append(" OR ");
}
}
return sb.toString();
}
public void addIndexableData(IndexableData data) { public void addIndexableData(IndexableData data) {
mDataToIndex.add(data); mDataToIndex.add(data);
} }
@@ -271,9 +290,9 @@ public class Index {
// Insert rows for the main PreferenceScreen node. Rewrite the data for removing // Insert rows for the main PreferenceScreen node. Rewrite the data for removing
// hyphens. // hyphens.
inserOneRowWithFilteredData(database, localeStr, title, summary, fragmentName, inserOneRowWithFilteredData(database, localeStr, title, summary, fragmentName,
fragmentTitle, iconResId, rank, keywords, "\u2011", ""); fragmentTitle, iconResId, rank, keywords, NON_BREAKING_HYPHEN, EMPTY);
inserOneRowWithFilteredData(database, localeStr, title, summary, fragmentName, inserOneRowWithFilteredData(database, localeStr, title, summary, fragmentName,
fragmentTitle, iconResId, rank, keywords, "\u2011", "-"); fragmentTitle, iconResId, rank, keywords, NON_BREAKING_HYPHEN, HYPHEN);
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {