package net.enilink.komma.core; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.regex.Pattern; public class SparqlStandardDialect implements IDialect { protected volatile int varCount = 0; private static Pattern ESCAPE_CHARS = Pattern.compile("[\\[.{(*+?^$|]"); /** * Creates a semi globally unique variable name by appending a global * counter value. * * @param prefix * The prefix for the variable name. * @return The variable name. */ protected String createVar(String prefix) { return prefix + Integer.toString(varCount++, Character.MAX_RADIX); } protected String createRegexForPattern(String searchPattern, int flags) { searchPattern = ESCAPE_CHARS.matcher(searchPattern) .replaceAll("\\\\$0"); return searchPattern.replace("\\*", ".*").replace("\\?", "."); } protected String[] filterEmpty(String[] patterns) { List<String> nonEmpty = new ArrayList<String>(patterns.length); for (String pattern : patterns) { if (pattern != null) { pattern = pattern.trim(); if (pattern.length() > 0) { nonEmpty.add(pattern); } } } return nonEmpty.toArray(new String[nonEmpty.size()]); } /** * This implementation simply uses the SPARQL regex built-in function to * execute the search. While supported by all triple stores the performance * of this implementation may be rather slow. */ @Override public QueryFragment fullTextSearch( Collection<? extends String> bindingNames, int flags, String... patterns) { boolean caseSensitive = (flags & CASE_SENSITIVE) != 0; patterns = filterEmpty(patterns); if (patterns.length > 0) { LinkedHashBindings<Object> bindings = new LinkedHashBindings<Object>(); if ((flags & ALL) == 0) { StringBuilder regex = new StringBuilder(); for (int i = 0; i < patterns.length; i++) { String pattern = patterns[i]; regex.append(createRegexForPattern(pattern, flags)); if (i < patterns.length - 1) { regex.append("|"); } } String var = createVar("pattern_"); bindings.put(var, regex.toString()); StringBuilder filter = new StringBuilder(); for (String bindingName : bindingNames) { if (filter.length() > 0) { filter.append(" || "); } filter.append("regex(str(?" + bindingName + "), ?" + var + (caseSensitive ? "" : ", \"i\"") + ")"); } return new QueryFragment("FILTER (" + filter + ")", bindings); } else { List<String> vars = new ArrayList<String>(); for (String pattern : patterns) { String var = createVar("pattern_"); vars.add(var); bindings.put(var, createRegexForPattern(pattern, flags)); } StringBuilder filter = new StringBuilder(); for (String bindingName : bindingNames) { if (filter.length() > 0) { filter.append(" || "); } StringBuilder bindingFilter = new StringBuilder(); for (String var : vars) { if (bindingFilter.length() > 0) { bindingFilter.append(" && "); } bindingFilter .append("regex(str(?" + bindingName + "), ?") .append(var) .append(caseSensitive ? "" : ", \"i\"") .append(")"); } filter.append(bindingFilter); } return new QueryFragment("FILTER (" + filter + ")", bindings); } } return new QueryFragment(""); } }