【问题标题】:How to search special characters(+ ! \ ? : ) in Lucene如何在 Lucene 中搜索特殊字符(+ ! \ ? : )
【发布时间】:2011-05-24 08:47:07
【问题描述】:

我想在索引中搜索特殊字符。

我转义了查询字符串中的所有特殊字符,但是当我在索引中的 lucene 上执行查询为 + 时,它将查询创建为 +()。

因此它不搜索任何字段。

如何解决这个问题?我的索引包含这些特殊字符。

【问题讨论】:

  • 请举例说明您正在搜索的内容和创建的内容。 “查询为 +”是什么意思?
  • 我正在搜索特殊字符,例如 + ! ?等等。好吧,我得到了解决方案。实际上我们正在使用一些自定义分析器,并且由于应用了过滤器,它给出了空白查询(+())。但是当我使用 KeywordAnalyzer 时它起作用了。 有什么意见吗?
  • 您是否使用相同的分析器进行索引和查询?请添加一个代码示例,描述您的确切查询以及在调用搜索之前如何处理它。

标签: lucene


【解决方案1】:

如果您使用StandardAnalyzer,则会丢弃非字母数字字符。尝试使用 WhitespaceAnalyzer 索引相同的值,看看是否保留了您需要的字符。它还可能保留您不想要的东西:这时您可能会考虑编写自己的分析器,这基本上意味着创建一个 TokenStream 堆栈来执行您需要的处理。

例如,SimpleAnalyzer 实现了以下管道:

@Override
public TokenStream tokenStream(String fieldName, Reader reader) {
   return new LowerCaseTokenizer(reader);
}

只是将标记小写。

StandardAnalyzer 做得更多:

/** Constructs a {@link StandardTokenizer} filtered by a {@link
StandardFilter}, a {@link LowerCaseFilter} and a {@link StopFilter}. */
@Override
public TokenStream tokenStream(String fieldName, Reader reader) {
    StandardTokenizer tokenStream = new StandardTokenizer(matchVersion, reader);
    tokenStream.setMaxTokenLength(maxTokenLength);
    TokenStream result = new StandardFilter(tokenStream);
    result = new LowerCaseFilter(result);
    result = new StopFilter(enableStopPositionIncrements, result, stopSet);
    return result;
 }

您可以混合和匹配org.apache.lucene.analysis 中的这些和其他组件,或者您可以编写自己的专用TokenStream 实例,这些实例由您的自定义Analyzer 包装到处理管道中。

另一件需要注意的事情是您使用的是哪种CharTokenizerCharTokenizer 是一个抽象类,它指定了对文本字符串进行标记的机制。它被一些更简单的分析器使用(但不是StandardAnalyzer)。 Lucene 带有两个子类:LetterTokenizerWhitespaceTokenizer。您可以通过实现boolean isTokenChar(char c) 方法创建自己的字符,保留您需要的字符并中断不需要的字符。

【讨论】:

    【解决方案2】:

    也许对作者来说不是真的,但能够搜索到你需要的特殊字符:

    1. 创建自定义分析器
    2. 将其用于索引和搜索

    举例说明它对我的作用:

    import org.apache.lucene.analysis.Analyzer;
    import org.apache.lucene.analysis.custom.CustomAnalyzer;
    import org.apache.lucene.document.Document;
    import org.apache.lucene.document.Field;
    import org.apache.lucene.document.TextField;
    import org.apache.lucene.index.DirectoryReader;
    import org.apache.lucene.index.IndexReader;
    import org.apache.lucene.index.IndexWriter;
    import org.apache.lucene.index.IndexWriterConfig;
    import org.apache.lucene.queryparser.classic.QueryParser;
    import org.apache.lucene.search.*;
    import org.apache.lucene.store.RAMDirectory;
    import org.junit.Test;
    
    import java.io.IOException;
    
    import static org.hamcrest.Matchers.equalTo;
    import static org.junit.Assert.assertThat;
    
    public class LuceneSpecialCharactersSearchTest {
    
    /**
     * Test that tries to search a string by some substring with each special character separately.
     */
    @Test
    public void testSpecialCharacterSearch() throws Exception {
        // GIVEN
        LuceneSpecialCharactersSearch service = new LuceneSpecialCharactersSearch();
        String[] luceneSpecialCharacters = new String[]{"+", "-", "&&", "||", "!", "(", ")", "{", "}", "[", "]", "^", "\"", "~", "*", "?", ":", "\\"};
    
        // WHEN
        for (String specialCharacter : luceneSpecialCharacters) {
            String actual = service.search("list's special-characters " + specialCharacter);
    
            // THEN
            assertThat(actual, equalTo(LuceneSpecialCharactersSearch.TEXT_WITH_SPECIAL_CHARACTERS));
        }
    }
    
    private static class LuceneSpecialCharactersSearch {
        private static final String TEXT_WITH_SPECIAL_CHARACTERS = "This is the list's of special-characters + - && || ! ( ) { } [ ] ^ \" ~ ? : \\ *";
    
        private final IndexWriter writer;
    
        public LuceneSpecialCharactersSearch() throws Exception {
            Document document = new Document();
            document.add(new TextField("body", TEXT_WITH_SPECIAL_CHARACTERS, Field.Store.YES));
    
            RAMDirectory directory = new RAMDirectory();
            writer = new IndexWriter(directory, new IndexWriterConfig(buildAnalyzer()));
            writer.addDocument(document);
            writer.commit();
        }
    
        public String search(String queryString) throws Exception {
            try (IndexReader reader = DirectoryReader.open(writer, false)) {
                IndexSearcher searcher = new IndexSearcher(reader);
    
                String escapedQueryString = QueryParser.escape(queryString).toLowerCase();
    
                Analyzer analyzer = buildAnalyzer();
                QueryParser bodyQueryParser = new QueryParser("body", analyzer);
                bodyQueryParser.setDefaultOperator(QueryParser.Operator.AND);
    
    
                Query bodyQuery = bodyQueryParser.parse(escapedQueryString);
                BooleanQuery query = new BooleanQuery.Builder()
                        .add(new BooleanClause(bodyQuery, BooleanClause.Occur.SHOULD))
                        .build();
                TopDocs searchResult = searcher.search(query, 1);
    
                return searcher.doc(searchResult.scoreDocs[0].doc).getField("body").stringValue();
            }
        }
    
        /**
         * Builds analyzer that is used for indexing and searching.
         */
        private static Analyzer buildAnalyzer() throws IOException {
            return CustomAnalyzer.builder()
                    .withTokenizer("whitespace")
                    .addTokenFilter("lowercase")
                    .addTokenFilter("standard")
                    .build();
    
        }
    }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-10-24
      • 1970-01-01
      • 1970-01-01
      • 2017-05-22
      • 2018-08-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多