| using Lucene.Net.Analysis; |
| using Lucene.Net.Analysis.TokenAttributes; |
| using NUnit.Framework; |
| using System; |
| using System.IO; |
| using Assert = Lucene.Net.TestFramework.Assert; |
| |
| namespace Lucene.Net.Util |
| { |
| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| using Analyzer = Lucene.Net.Analysis.Analyzer; |
| using BooleanQuery = Lucene.Net.Search.BooleanQuery; |
| using CharacterRunAutomaton = Lucene.Net.Util.Automaton.CharacterRunAutomaton; |
| using MockAnalyzer = Lucene.Net.Analysis.MockAnalyzer; |
| using MockTokenizer = Lucene.Net.Analysis.MockTokenizer; |
| using MultiPhraseQuery = Lucene.Net.Search.MultiPhraseQuery; |
| using Occur = Lucene.Net.Search.Occur; |
| using PhraseQuery = Lucene.Net.Search.PhraseQuery; |
| using RegExp = Lucene.Net.Util.Automaton.RegExp; |
| using Term = Lucene.Net.Index.Term; |
| using TermQuery = Lucene.Net.Search.TermQuery; |
| using TokenFilter = Lucene.Net.Analysis.TokenFilter; |
| using Tokenizer = Lucene.Net.Analysis.Tokenizer; |
| using TokenStream = Lucene.Net.Analysis.TokenStream; |
| |
| [TestFixture] |
| public class TestQueryBuilder : LuceneTestCase |
| { |
| [Test] |
| public virtual void TestTerm() |
| { |
| TermQuery expected = new TermQuery(new Term("field", "test")); |
| QueryBuilder builder = new QueryBuilder(new MockAnalyzer(Random)); |
| Assert.AreEqual(expected, builder.CreateBooleanQuery("field", "test")); |
| } |
| |
| [Test] |
| public virtual void TestBoolean() |
| { |
| BooleanQuery expected = new BooleanQuery(); |
| expected.Add(new TermQuery(new Term("field", "foo")), Occur.SHOULD); |
| expected.Add(new TermQuery(new Term("field", "bar")), Occur.SHOULD); |
| QueryBuilder builder = new QueryBuilder(new MockAnalyzer(Random)); |
| Assert.IsTrue(expected.Equals(builder.CreateBooleanQuery("field", "foo bar"))); |
| //Assert.AreEqual(expected, builder.CreateBooleanQuery("field", "foo bar")); |
| } |
| |
| [Test] |
| public virtual void TestBooleanMust() |
| { |
| BooleanQuery expected = new BooleanQuery(); |
| expected.Add(new TermQuery(new Term("field", "foo")), Occur.MUST); |
| expected.Add(new TermQuery(new Term("field", "bar")), Occur.MUST); |
| QueryBuilder builder = new QueryBuilder(new MockAnalyzer(Random)); |
| Assert.AreEqual(expected, builder.CreateBooleanQuery("field", "foo bar", Occur.MUST)); |
| } |
| |
| [Test] |
| public virtual void TestMinShouldMatchNone() |
| { |
| QueryBuilder builder = new QueryBuilder(new MockAnalyzer(Random)); |
| Assert.AreEqual(builder.CreateBooleanQuery("field", "one two three four"), builder.CreateMinShouldMatchQuery("field", "one two three four", 0f)); |
| } |
| |
| [Test] |
| public virtual void TestMinShouldMatchAll() |
| { |
| QueryBuilder builder = new QueryBuilder(new MockAnalyzer(Random)); |
| Assert.AreEqual(builder.CreateBooleanQuery("field", "one two three four", Occur.MUST), builder.CreateMinShouldMatchQuery("field", "one two three four", 1f)); |
| } |
| |
| [Test] |
| public virtual void TestMinShouldMatch() |
| { |
| BooleanQuery expected = new BooleanQuery(); |
| expected.Add(new TermQuery(new Term("field", "one")), Occur.SHOULD); |
| expected.Add(new TermQuery(new Term("field", "two")), Occur.SHOULD); |
| expected.Add(new TermQuery(new Term("field", "three")), Occur.SHOULD); |
| expected.Add(new TermQuery(new Term("field", "four")), Occur.SHOULD); |
| expected.MinimumNumberShouldMatch = 0; |
| |
| QueryBuilder builder = new QueryBuilder(new MockAnalyzer(Random)); |
| Assert.AreEqual(expected, builder.CreateMinShouldMatchQuery("field", "one two three four", 0.1f)); |
| Assert.AreEqual(expected, builder.CreateMinShouldMatchQuery("field", "one two three four", 0.24f)); |
| |
| expected.MinimumNumberShouldMatch = 1; |
| Assert.AreEqual(expected, builder.CreateMinShouldMatchQuery("field", "one two three four", 0.25f)); |
| Assert.AreEqual(expected, builder.CreateMinShouldMatchQuery("field", "one two three four", 0.49f)); |
| |
| expected.MinimumNumberShouldMatch = 2; |
| Assert.AreEqual(expected, builder.CreateMinShouldMatchQuery("field", "one two three four", 0.5f)); |
| Assert.AreEqual(expected, builder.CreateMinShouldMatchQuery("field", "one two three four", 0.74f)); |
| |
| expected.MinimumNumberShouldMatch = 3; |
| Assert.AreEqual(expected, builder.CreateMinShouldMatchQuery("field", "one two three four", 0.75f)); |
| Assert.AreEqual(expected, builder.CreateMinShouldMatchQuery("field", "one two three four", 0.99f)); |
| } |
| |
| [Test] |
| public virtual void TestPhraseQueryPositionIncrements() |
| { |
| PhraseQuery expected = new PhraseQuery(); |
| expected.Add(new Term("field", "1")); |
| expected.Add(new Term("field", "2"), 2); |
| |
| CharacterRunAutomaton stopList = new CharacterRunAutomaton((new RegExp("[sS][tT][oO][pP]")).ToAutomaton()); |
| |
| Analyzer analyzer = new MockAnalyzer(Random, MockTokenizer.WHITESPACE, false, stopList); |
| |
| QueryBuilder builder = new QueryBuilder(analyzer); |
| Assert.AreEqual(expected, builder.CreatePhraseQuery("field", "1 stop 2")); |
| } |
| |
| [Test] |
| public virtual void TestEmpty() |
| { |
| QueryBuilder builder = new QueryBuilder(new MockAnalyzer(Random)); |
| Assert.IsNull(builder.CreateBooleanQuery("field", "")); |
| } |
| |
| /// <summary> |
| /// adds synonym of "dog" for "dogs". </summary> |
| internal class MockSynonymAnalyzer : Analyzer |
| { |
| protected internal override TokenStreamComponents CreateComponents(string fieldName, TextReader reader) |
| { |
| MockTokenizer tokenizer = new MockTokenizer(reader); |
| return new TokenStreamComponents(tokenizer, new MockSynonymFilter(tokenizer)); |
| } |
| } |
| |
| /// <summary> |
| /// adds synonym of "dog" for "dogs". |
| /// </summary> |
| protected internal class MockSynonymFilter : TokenFilter |
| { |
| private readonly ICharTermAttribute termAtt; |
| private readonly IPositionIncrementAttribute posIncAtt; |
| private bool addSynonym = false; |
| |
| public MockSynonymFilter(TokenStream input) |
| : base(input) |
| { |
| termAtt = AddAttribute<ICharTermAttribute>(); |
| posIncAtt = AddAttribute<IPositionIncrementAttribute>(); |
| } |
| |
| public sealed override bool IncrementToken() |
| { |
| if (addSynonym) // inject our synonym |
| { |
| ClearAttributes(); |
| termAtt.SetEmpty().Append("dog"); |
| posIncAtt.PositionIncrement = 0; |
| addSynonym = false; |
| return true; |
| } |
| |
| if (m_input.IncrementToken()) |
| { |
| addSynonym = termAtt.ToString().Equals("dogs", StringComparison.Ordinal); |
| return true; |
| } |
| else |
| { |
| return false; |
| } |
| } |
| } |
| |
| /// <summary> |
| /// simple synonyms test </summary> |
| [Test] |
| public virtual void TestSynonyms() |
| { |
| BooleanQuery expected = new BooleanQuery(true); |
| expected.Add(new TermQuery(new Term("field", "dogs")), Occur.SHOULD); |
| expected.Add(new TermQuery(new Term("field", "dog")), Occur.SHOULD); |
| QueryBuilder builder = new QueryBuilder(new MockSynonymAnalyzer()); |
| Assert.AreEqual(expected, builder.CreateBooleanQuery("field", "dogs")); |
| Assert.AreEqual(expected, builder.CreatePhraseQuery("field", "dogs")); |
| Assert.AreEqual(expected, builder.CreateBooleanQuery("field", "dogs", Occur.MUST)); |
| Assert.AreEqual(expected, builder.CreatePhraseQuery("field", "dogs")); |
| } |
| |
| /// <summary> |
| /// forms multiphrase query </summary> |
| [Test] |
| public virtual void TestSynonymsPhrase() |
| { |
| MultiPhraseQuery expected = new MultiPhraseQuery(); |
| expected.Add(new Term("field", "old")); |
| expected.Add(new Term[] { new Term("field", "dogs"), new Term("field", "dog") }); |
| QueryBuilder builder = new QueryBuilder(new MockSynonymAnalyzer()); |
| Assert.AreEqual(expected, builder.CreatePhraseQuery("field", "old dogs")); |
| } |
| |
| protected internal class SimpleCJKTokenizer : Tokenizer |
| { |
| private readonly ICharTermAttribute termAtt; |
| |
| public SimpleCJKTokenizer(TextReader input) |
| : base(input) |
| { |
| termAtt = AddAttribute<ICharTermAttribute>(); |
| } |
| |
| public sealed override bool IncrementToken() |
| { |
| int ch = m_input.Read(); |
| if (ch < 0) |
| { |
| return false; |
| } |
| ClearAttributes(); |
| termAtt.SetEmpty().Append((char)ch); |
| return true; |
| } |
| } |
| |
| private class SimpleCJKAnalyzer : Analyzer |
| { |
| protected internal override TokenStreamComponents CreateComponents(string fieldName, TextReader reader) |
| { |
| return new TokenStreamComponents(new SimpleCJKTokenizer(reader)); |
| } |
| } |
| |
| [Test] |
| public virtual void TestCJKTerm() |
| { |
| // individual CJK chars as terms |
| SimpleCJKAnalyzer analyzer = new SimpleCJKAnalyzer(); |
| |
| BooleanQuery expected = new BooleanQuery(); |
| expected.Add(new TermQuery(new Term("field", "中")), Occur.SHOULD); |
| expected.Add(new TermQuery(new Term("field", "国")), Occur.SHOULD); |
| |
| QueryBuilder builder = new QueryBuilder(analyzer); |
| Assert.AreEqual(expected, builder.CreateBooleanQuery("field", "中国")); |
| } |
| |
| [Test] |
| public virtual void TestCJKPhrase() |
| { |
| // individual CJK chars as terms |
| SimpleCJKAnalyzer analyzer = new SimpleCJKAnalyzer(); |
| |
| PhraseQuery expected = new PhraseQuery(); |
| expected.Add(new Term("field", "中")); |
| expected.Add(new Term("field", "国")); |
| |
| QueryBuilder builder = new QueryBuilder(analyzer); |
| Assert.AreEqual(expected, builder.CreatePhraseQuery("field", "中国")); |
| } |
| |
| [Test] |
| public virtual void TestCJKSloppyPhrase() |
| { |
| // individual CJK chars as terms |
| SimpleCJKAnalyzer analyzer = new SimpleCJKAnalyzer(); |
| |
| PhraseQuery expected = new PhraseQuery(); |
| expected.Slop = 3; |
| expected.Add(new Term("field", "中")); |
| expected.Add(new Term("field", "国")); |
| |
| QueryBuilder builder = new QueryBuilder(analyzer); |
| Assert.AreEqual(expected, builder.CreatePhraseQuery("field", "中国", 3)); |
| } |
| |
| /// <summary> |
| /// adds synonym of "國" for "国". |
| /// </summary> |
| protected internal class MockCJKSynonymFilter : TokenFilter |
| { |
| private readonly ICharTermAttribute termAtt; |
| private readonly IPositionIncrementAttribute posIncAtt; |
| private bool addSynonym = false; |
| |
| public MockCJKSynonymFilter(TokenStream input) |
| : base(input) |
| { |
| termAtt = AddAttribute<ICharTermAttribute>(); |
| posIncAtt = AddAttribute<IPositionIncrementAttribute>(); |
| } |
| |
| public sealed override bool IncrementToken() |
| { |
| if (addSynonym) // inject our synonym |
| { |
| ClearAttributes(); |
| termAtt.SetEmpty().Append("國"); |
| posIncAtt.PositionIncrement = 0; |
| addSynonym = false; |
| return true; |
| } |
| |
| if (m_input.IncrementToken()) |
| { |
| addSynonym = termAtt.ToString().Equals("国", StringComparison.Ordinal); |
| return true; |
| } |
| else |
| { |
| return false; |
| } |
| } |
| } |
| |
| internal class MockCJKSynonymAnalyzer : Analyzer |
| { |
| protected internal override TokenStreamComponents CreateComponents(string fieldName, TextReader reader) |
| { |
| Tokenizer tokenizer = new SimpleCJKTokenizer(reader); |
| return new TokenStreamComponents(tokenizer, new MockCJKSynonymFilter(tokenizer)); |
| } |
| } |
| |
| /// <summary> |
| /// simple CJK synonym test </summary> |
| [Test] |
| public virtual void TestCJKSynonym() |
| { |
| BooleanQuery expected = new BooleanQuery(true); |
| expected.Add(new TermQuery(new Term("field", "国")), Occur.SHOULD); |
| expected.Add(new TermQuery(new Term("field", "國")), Occur.SHOULD); |
| QueryBuilder builder = new QueryBuilder(new MockCJKSynonymAnalyzer()); |
| Assert.AreEqual(expected, builder.CreateBooleanQuery("field", "国")); |
| Assert.AreEqual(expected, builder.CreatePhraseQuery("field", "国")); |
| Assert.AreEqual(expected, builder.CreateBooleanQuery("field", "国", Occur.MUST)); |
| } |
| |
| /// <summary> |
| /// synonyms with default OR operator </summary> |
| [Test] |
| public virtual void TestCJKSynonymsOR() |
| { |
| BooleanQuery expected = new BooleanQuery(); |
| expected.Add(new TermQuery(new Term("field", "中")), Occur.SHOULD); |
| BooleanQuery inner = new BooleanQuery(true); |
| inner.Add(new TermQuery(new Term("field", "国")), Occur.SHOULD); |
| inner.Add(new TermQuery(new Term("field", "國")), Occur.SHOULD); |
| expected.Add(inner, Occur.SHOULD); |
| QueryBuilder builder = new QueryBuilder(new MockCJKSynonymAnalyzer()); |
| Assert.AreEqual(expected, builder.CreateBooleanQuery("field", "中国")); |
| } |
| |
| /// <summary> |
| /// more complex synonyms with default OR operator </summary> |
| [Test] |
| public virtual void TestCJKSynonymsOR2() |
| { |
| BooleanQuery expected = new BooleanQuery(); |
| expected.Add(new TermQuery(new Term("field", "中")), Occur.SHOULD); |
| BooleanQuery inner = new BooleanQuery(true); |
| inner.Add(new TermQuery(new Term("field", "国")), Occur.SHOULD); |
| inner.Add(new TermQuery(new Term("field", "國")), Occur.SHOULD); |
| expected.Add(inner, Occur.SHOULD); |
| BooleanQuery inner2 = new BooleanQuery(true); |
| inner2.Add(new TermQuery(new Term("field", "国")), Occur.SHOULD); |
| inner2.Add(new TermQuery(new Term("field", "國")), Occur.SHOULD); |
| expected.Add(inner2, Occur.SHOULD); |
| QueryBuilder builder = new QueryBuilder(new MockCJKSynonymAnalyzer()); |
| Assert.AreEqual(expected, builder.CreateBooleanQuery("field", "中国国")); |
| } |
| |
| /// <summary> |
| /// synonyms with default AND operator </summary> |
| [Test] |
| public virtual void TestCJKSynonymsAND() |
| { |
| BooleanQuery expected = new BooleanQuery(); |
| expected.Add(new TermQuery(new Term("field", "中")), Occur.MUST); |
| BooleanQuery inner = new BooleanQuery(true); |
| inner.Add(new TermQuery(new Term("field", "国")), Occur.SHOULD); |
| inner.Add(new TermQuery(new Term("field", "國")), Occur.SHOULD); |
| expected.Add(inner, Occur.MUST); |
| QueryBuilder builder = new QueryBuilder(new MockCJKSynonymAnalyzer()); |
| Assert.AreEqual(expected, builder.CreateBooleanQuery("field", "中国", Occur.MUST)); |
| } |
| |
| /// <summary> |
| /// more complex synonyms with default AND operator </summary> |
| [Test] |
| public virtual void TestCJKSynonymsAND2() |
| { |
| BooleanQuery expected = new BooleanQuery(); |
| expected.Add(new TermQuery(new Term("field", "中")), Occur.MUST); |
| BooleanQuery inner = new BooleanQuery(true); |
| inner.Add(new TermQuery(new Term("field", "国")), Occur.SHOULD); |
| inner.Add(new TermQuery(new Term("field", "國")), Occur.SHOULD); |
| expected.Add(inner, Occur.MUST); |
| BooleanQuery inner2 = new BooleanQuery(true); |
| inner2.Add(new TermQuery(new Term("field", "国")), Occur.SHOULD); |
| inner2.Add(new TermQuery(new Term("field", "國")), Occur.SHOULD); |
| expected.Add(inner2, Occur.MUST); |
| QueryBuilder builder = new QueryBuilder(new MockCJKSynonymAnalyzer()); |
| Assert.AreEqual(expected, builder.CreateBooleanQuery("field", "中国国", Occur.MUST)); |
| } |
| |
| /// <summary> |
| /// forms multiphrase query </summary> |
| [Test] |
| public virtual void TestCJKSynonymsPhrase() |
| { |
| MultiPhraseQuery expected = new MultiPhraseQuery(); |
| expected.Add(new Term("field", "中")); |
| expected.Add(new Term[] { new Term("field", "国"), new Term("field", "國") }); |
| QueryBuilder builder = new QueryBuilder(new MockCJKSynonymAnalyzer()); |
| Assert.AreEqual(expected, builder.CreatePhraseQuery("field", "中国")); |
| expected.Slop = 3; |
| Assert.AreEqual(expected, builder.CreatePhraseQuery("field", "中国", 3)); |
| } |
| } |
| } |