
com.xlrit.gears.engine.search.PostgresSearchAdapter Maven / Gradle / Ivy
package com.xlrit.gears.engine.search;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import com.xlrit.gears.base.repository.JpaRepository;
import com.xlrit.gears.engine.meta.EntityInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A tsquery value stores lexemes that are to be searched for, and can combine them using the Boolean operators & (AND), | (OR), and ! (NOT), as well as the phrase search operator <-> (FOLLOWED BY).
* There is also a variant of the FOLLOWED BY operator, where N is an integer constant that specifies the distance between the two lexemes being searched for. <-> is equivalent to <1>.
*
* to_tsquery creates a tsquery value from querytext, which must consist of single tokens separated by the tsquery operators & (AND), | (OR), ! (NOT), and <-> (FOLLOWED BY), possibly grouped using parentheses.
* In other words, the input to to_tsquery must already follow the general rules for tsquery input, as described in Section 8.11.2.
* The difference is that while basic tsquery input takes the tokens at face value, to_tsquery normalizes each token into a lexeme using the specified or default configuration, and discards any tokens that are stop words according to the configuration.
*/
public class PostgresSearchAdapter extends DefaultSearchAdapter {
private static final Logger LOG = LoggerFactory.getLogger(PostgresSearchAdapter.class);
private final String searchLanguage;
public PostgresSearchAdapter(String defaultMode, String searchLanguage) {
super(defaultMode);
this.searchLanguage = searchLanguage;
}
@Override
public void logSearchIndex(String name, EntityInfo> entityInfo, List fieldNames) {
if (entityInfo.getRepository() instanceof JpaRepository> repository) {
String tableName = repository.getTableName();
String indexName = tableName + "_search";
List columnNames = repository.getColumnNames(fieldNames);
if (tableName != null && columnNames != null) {
LOG.info("CREATE INDEX {} ON {} USING GIN (to_tsvector('{}', concat_ws(' ', {})));", indexName, tableName, searchLanguage, String.join(", ", columnNames));
}
else {
LOG.info("-- Unable to generate search index for {} (tableName={}, columnNames={})", name, tableName, columnNames);
}
}
}
@Override
protected String toAdvancedSearchTerm(String querytext) {
// adapt the search input as an argument to `to_tsquery`
// special characters: - _ . ( ) & # + TODO what about "/" and ","?
// we can keep . but need to escape the rest
String stripped = querytext.replaceAll("([-_()!])", "\\\\$1");
String[] words = stripped.split("\\s+");
return Arrays.stream(words)
.map(word -> word + ":*")
.collect(Collectors.joining(" & "));
}
@Override
public String toString() {
return "PostgresSearchAdapter[" +
"language='" + searchLanguage + '\'' +
']';
}
}