/** @return Returns true if the pattern is present, otherwise false. */
  public boolean contains(
      NodeRef nodeRef,
      QName propertyQName,
      String googleLikePattern,
      SearchParameters.Operator defaultOperator) {
    ResultSet resultSet = null;
    try {
      // build Lucene search string specific to the node
      StringBuilder sb = new StringBuilder();
      sb.append("+ID:\"")
          .append(nodeRef.toString())
          .append("\" +(TEXT:(")
          .append(googleLikePattern.toLowerCase())
          .append(") ");
      if (propertyQName != null) {
        sb.append(" OR @")
            .append(
                SearchLanguageConversion.escapeLuceneQuery(
                    QName.createQName(
                            propertyQName.getNamespaceURI(),
                            ISO9075.encode(propertyQName.getLocalName()))
                        .toString()));
        sb.append(":(").append(googleLikePattern.toLowerCase()).append(")");
      } else {
        for (QName key : nodeService.getProperties(nodeRef).keySet()) {
          sb.append(" OR @")
              .append(
                  SearchLanguageConversion.escapeLuceneQuery(
                      QName.createQName(key.getNamespaceURI(), ISO9075.encode(key.getLocalName()))
                          .toString()));
          sb.append(":(").append(googleLikePattern.toLowerCase()).append(")");
        }
      }
      sb.append(")");

      SearchParameters sp = new SearchParameters();
      sp.setLanguage(SearchService.LANGUAGE_LUCENE);
      sp.setQuery(sb.toString());
      sp.setDefaultOperator(defaultOperator);
      sp.addStore(nodeRef.getStoreRef());

      resultSet = this.query(sp);
      boolean answer = resultSet.length() > 0;
      return answer;
    } finally {
      if (resultSet != null) {
        resultSet.close();
      }
    }
  }
  /** @return Returns true if the pattern is present, otherwise false. */
  public boolean like(
      NodeRef nodeRef, QName propertyQName, String sqlLikePattern, boolean includeFTS) {
    if (propertyQName == null) {
      throw new IllegalArgumentException("Property QName is mandatory for the like expression");
    }

    StringBuilder sb = new StringBuilder(sqlLikePattern.length() * 3);

    if (includeFTS) {
      // convert the SQL-like pattern into a Lucene-compatible string
      String pattern =
          SearchLanguageConversion.convertXPathLikeToLucene(sqlLikePattern.toLowerCase());

      // build Lucene search string specific to the node
      sb = new StringBuilder();
      sb.append("+ID:\"").append(nodeRef.toString()).append("\" +(");
      // FTS or attribute matches
      if (includeFTS) {
        sb.append("TEXT:(").append(pattern).append(") ");
      }
      if (propertyQName != null) {
        sb.append(" @")
            .append(
                SearchLanguageConversion.escapeLuceneQuery(
                    QName.createQName(
                            propertyQName.getNamespaceURI(),
                            ISO9075.encode(propertyQName.getLocalName()))
                        .toString()))
            .append(":(")
            .append(pattern)
            .append(")");
      }
      sb.append(")");

      ResultSet resultSet = null;
      try {
        resultSet = this.query(nodeRef.getStoreRef(), "lucene", sb.toString());
        boolean answer = resultSet.length() > 0;
        return answer;
      } finally {
        if (resultSet != null) {
          resultSet.close();
        }
      }
    } else {
      // convert the SQL-like pattern into a Lucene-compatible string
      String pattern =
          SearchLanguageConversion.convertXPathLikeToRegex(sqlLikePattern.toLowerCase());

      Serializable property = nodeService.getProperty(nodeRef, propertyQName);
      if (property == null) {
        return false;
      } else {
        String propertyString =
            DefaultTypeConverter.INSTANCE.convert(
                String.class, nodeService.getProperty(nodeRef, propertyQName));
        return propertyString.toLowerCase().matches(pattern);
      }
    }
  }