You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucenenet.apache.org by sy...@apache.org on 2016/09/11 21:30:53 UTC
[22/50] [abbrv] lucenenet git commit: Moved Lucene.Net.QueryParser
and Lucene.Net.Tests.QueryParser projects into src\ directory.
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/679ad24c/src/Lucene.Net.QueryParser/Surround/Query/ComposedQuery.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Surround/Query/ComposedQuery.cs b/src/Lucene.Net.QueryParser/Surround/Query/ComposedQuery.cs
new file mode 100644
index 0000000..d421ad6
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Surround/Query/ComposedQuery.cs
@@ -0,0 +1,144 @@
+\ufeffusing System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Lucene.Net.QueryParser.Surround.Query
+{
+ /*
+ * 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.
+ */
+
+ /// <summary>
+ /// Base class for composite queries (such as AND/OR/NOT)
+ /// </summary>
+ public abstract class ComposedQuery : SrndQuery
+ {
+ public ComposedQuery(IEnumerable<SrndQuery> qs, bool operatorInfix, string opName)
+ {
+ Recompose(qs);
+ this.operatorInfix = operatorInfix;
+ this.opName = opName;
+ }
+
+ protected virtual void Recompose(IEnumerable<SrndQuery> queries)
+ {
+ if (queries.Count() < 2) throw new InvalidOperationException("Too few subqueries");
+ this.queries = new List<SrndQuery>(queries);
+ }
+
+ protected string opName;
+ public virtual string OperatorName { get { return opName; } }
+
+ protected IList<SrndQuery> queries;
+
+ public virtual IEnumerator<SrndQuery> GetSubQueriesEnumerator()
+ {
+ return queries.GetEnumerator();
+ }
+
+ public virtual int NrSubQueries { get { return queries.Count; } }
+
+ public virtual SrndQuery GetSubQuery(int qn) { return queries[qn]; }
+
+ private bool operatorInfix;
+ public virtual bool IsOperatorInfix { get { return operatorInfix; } } /* else prefix operator */
+
+ public IEnumerable<Search.Query> MakeLuceneSubQueriesField(string fn, BasicQueryFactory qf)
+ {
+ List<Search.Query> luceneSubQueries = new List<Search.Query>();
+ IEnumerator<SrndQuery> sqi = GetSubQueriesEnumerator();
+ while (sqi.MoveNext())
+ {
+ luceneSubQueries.Add((sqi.Current).MakeLuceneQueryField(fn, qf));
+ }
+ return luceneSubQueries;
+ }
+
+ public override string ToString()
+ {
+ StringBuilder r = new StringBuilder();
+ if (IsOperatorInfix)
+ {
+ InfixToString(r);
+ }
+ else
+ {
+ PrefixToString(r);
+ }
+ WeightToString(r);
+ return r.ToString();
+ }
+
+ // Override for different spacing
+ protected virtual string PrefixSeparator { get { return ", "; } }
+ protected virtual string BracketOpen { get { return "("; } }
+ protected virtual string BracketClose { get { return ")"; } }
+
+ protected virtual void InfixToString(StringBuilder r)
+ {
+ /* Brackets are possibly redundant in the result. */
+ IEnumerator<SrndQuery> sqi = GetSubQueriesEnumerator();
+ r.Append(BracketOpen);
+ if (sqi.MoveNext())
+ {
+ r.Append(sqi.Current.ToString());
+ while (sqi.MoveNext())
+ {
+ r.Append(" ");
+ r.Append(OperatorName); /* infix operator */
+ r.Append(" ");
+ r.Append(sqi.Current.ToString());
+ }
+ }
+ r.Append(BracketClose);
+ }
+
+ protected virtual void PrefixToString(StringBuilder r)
+ {
+ IEnumerator<SrndQuery> sqi = GetSubQueriesEnumerator();
+ r.Append(OperatorName); /* prefix operator */
+ r.Append(BracketOpen);
+ if (sqi.MoveNext())
+ {
+ r.Append(sqi.Current.ToString());
+ while (sqi.MoveNext())
+ {
+ r.Append(PrefixSeparator);
+ r.Append(sqi.Current.ToString());
+ }
+ }
+ r.Append(BracketClose);
+ }
+
+ public override bool IsFieldsSubQueryAcceptable
+ {
+ get
+ {
+ /* at least one subquery should be acceptable */
+ IEnumerator<SrndQuery> sqi = GetSubQueriesEnumerator();
+ while (sqi.MoveNext())
+ {
+ if ((sqi.Current).IsFieldsSubQueryAcceptable)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/679ad24c/src/Lucene.Net.QueryParser/Surround/Query/DistanceQuery.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Surround/Query/DistanceQuery.cs b/src/Lucene.Net.QueryParser/Surround/Query/DistanceQuery.cs
new file mode 100644
index 0000000..1ca7a01
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Surround/Query/DistanceQuery.cs
@@ -0,0 +1,117 @@
+\ufeffusing Lucene.Net.Index;
+using Lucene.Net.Search.Spans;
+using System;
+using System.Collections.Generic;
+
+namespace Lucene.Net.QueryParser.Surround.Query
+{
+ /*
+ * 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.
+ */
+
+ /// <summary>
+ /// Factory for NEAR queries
+ /// </summary>
+ public class DistanceQuery : ComposedQuery, IDistanceSubQuery
+ {
+ public DistanceQuery(
+ IEnumerable<SrndQuery> queries,
+ bool infix,
+ int opDistance,
+ string opName,
+ bool ordered)
+ : base(queries, infix, opName)
+ {
+ this.opDistance = opDistance; /* the distance indicated in the operator */
+ this.ordered = ordered;
+ }
+
+ private int opDistance;
+ public virtual int OpDistance { get { return opDistance; } }
+
+ private bool ordered;
+ public virtual bool QueriesOrdered { get { return ordered; } }
+
+
+ public virtual string DistanceSubQueryNotAllowed()
+ {
+ var sqi = GetSubQueriesEnumerator();
+ while (sqi.MoveNext())
+ {
+ var dsq = sqi.Current as IDistanceSubQuery;
+ if (dsq != null)
+ {
+ string m = dsq.DistanceSubQueryNotAllowed();
+ if (m != null)
+ {
+ return m;
+ }
+ }
+ else
+ {
+ return "Operator " + OperatorName + " does not allow subquery " + dsq.ToString();
+ }
+ }
+ return null; /* subqueries acceptable */
+ }
+
+ public virtual void AddSpanQueries(SpanNearClauseFactory sncf)
+ {
+ Search.Query snq = GetSpanNearQuery(sncf.IndexReader,
+ sncf.FieldName,
+ Weight,
+ sncf.BasicQueryFactory);
+ sncf.AddSpanQuery(snq);
+ }
+
+ public Search.Query GetSpanNearQuery(
+ IndexReader reader,
+ String fieldName,
+ float boost,
+ BasicQueryFactory qf)
+ {
+ SpanQuery[] spanClauses = new SpanQuery[NrSubQueries];
+ var sqi = GetSubQueriesEnumerator();
+ int qi = 0;
+ while (sqi.MoveNext())
+ {
+ SpanNearClauseFactory sncf = new SpanNearClauseFactory(reader, fieldName, qf);
+
+ ((IDistanceSubQuery)sqi.Current).AddSpanQueries(sncf);
+ if (sncf.Count == 0)
+ { /* distance operator requires all sub queries */
+ while (sqi.MoveNext())
+ { /* produce evt. error messages but ignore results */
+ ((IDistanceSubQuery)sqi.Current).AddSpanQueries(sncf);
+ sncf.Clear();
+ }
+ return SrndQuery.TheEmptyLcnQuery;
+ }
+
+ spanClauses[qi] = sncf.MakeSpanClause();
+ qi++;
+ }
+ SpanNearQuery r = new SpanNearQuery(spanClauses, OpDistance - 1, QueriesOrdered);
+ r.Boost = boost;
+ return r;
+ }
+
+ public override Search.Query MakeLuceneQueryFieldNoBoost(string fieldName, BasicQueryFactory qf)
+ {
+ return new DistanceRewriteQuery(this, fieldName, qf);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/679ad24c/src/Lucene.Net.QueryParser/Surround/Query/DistanceRewriteQuery.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Surround/Query/DistanceRewriteQuery.cs b/src/Lucene.Net.QueryParser/Surround/Query/DistanceRewriteQuery.cs
new file mode 100644
index 0000000..3d3a108
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Surround/Query/DistanceRewriteQuery.cs
@@ -0,0 +1,35 @@
+\ufeffnamespace Lucene.Net.QueryParser.Surround.Query
+{
+ /*
+ * 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.
+ */
+
+ internal class DistanceRewriteQuery : RewriteQuery<DistanceQuery>
+ {
+ public DistanceRewriteQuery(
+ DistanceQuery srndQuery,
+ string fieldName,
+ BasicQueryFactory qf)
+ : base(srndQuery, fieldName, qf)
+ {
+ }
+
+ public override Search.Query Rewrite(Index.IndexReader reader)
+ {
+ return srndQuery.GetSpanNearQuery(reader, fieldName, Boost, qf);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/679ad24c/src/Lucene.Net.QueryParser/Surround/Query/DistanceSubQuery.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Surround/Query/DistanceSubQuery.cs b/src/Lucene.Net.QueryParser/Surround/Query/DistanceSubQuery.cs
new file mode 100644
index 0000000..639f9e0
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Surround/Query/DistanceSubQuery.cs
@@ -0,0 +1,36 @@
+\ufeffnamespace Lucene.Net.QueryParser.Surround.Query
+{
+ /*
+ * 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.
+ */
+
+ /// <summary>
+ /// Interface for queries that can be nested as subqueries
+ /// into a span near.
+ /// </summary>
+ public interface IDistanceSubQuery
+ {
+ /// <summary>
+ /// When distanceSubQueryNotAllowed() returns non null, the reason why the subquery
+ /// is not allowed as a distance subquery is returned.
+ /// <br>When distanceSubQueryNotAllowed() returns null addSpanNearQueries() can be used
+ /// in the creation of the span near clause for the subquery.
+ /// </summary>
+ string DistanceSubQueryNotAllowed();
+
+ void AddSpanQueries(SpanNearClauseFactory sncf);
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/679ad24c/src/Lucene.Net.QueryParser/Surround/Query/FieldsQuery.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Surround/Query/FieldsQuery.cs b/src/Lucene.Net.QueryParser/Surround/Query/FieldsQuery.cs
new file mode 100644
index 0000000..912bf36
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Surround/Query/FieldsQuery.cs
@@ -0,0 +1,105 @@
+\ufeffusing System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Lucene.Net.QueryParser.Surround.Query
+{
+ /*
+ * 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.
+ */
+
+ /// <summary>
+ /// Forms an OR query of the provided query across multiple fields.
+ /// </summary>
+ public class FieldsQuery : SrndQuery /* mostly untested */
+ {
+ private SrndQuery q;
+ private IEnumerable<string> fieldNames;
+ private readonly char fieldOp;
+ private readonly string OrOperatorName = "OR"; /* for expanded queries, not normally visible */
+
+ public FieldsQuery(SrndQuery q, IEnumerable<string> fieldNames, char fieldOp)
+ {
+ this.q = q;
+ this.fieldNames = new List<string>(fieldNames);
+ this.fieldOp = fieldOp;
+ }
+
+ public FieldsQuery(SrndQuery q, string fieldName, char fieldOp)
+ {
+ this.q = q;
+ var fieldNameList = new List<string>();
+ fieldNameList.Add(fieldName);
+ this.fieldNames = fieldNameList;
+ this.fieldOp = fieldOp;
+ }
+
+ public override bool IsFieldsSubQueryAcceptable
+ {
+ get { return false; }
+ }
+
+ public Search.Query MakeLuceneQueryNoBoost(BasicQueryFactory qf)
+ {
+ if (fieldNames.Count() == 1)
+ { /* single field name: no new queries needed */
+ return q.MakeLuceneQueryFieldNoBoost(fieldNames.FirstOrDefault(), qf);
+ }
+ else
+ { /* OR query over the fields */
+ List<SrndQuery> queries = new List<SrndQuery>();
+ foreach (var fieldName in fieldNames)
+ {
+ var qc = (SrndQuery)q.Clone();
+ queries.Add(new FieldsQuery(qc, fieldName, fieldOp));
+ }
+ OrQuery oq = new OrQuery(queries,
+ true /* infix OR for field names */,
+ OrOperatorName);
+ // System.out.println(getClass().toString() + ", fields expanded: " + oq.toString()); /* needs testing */
+ return oq.MakeLuceneQueryField(null, qf);
+ }
+ }
+
+ public override Search.Query MakeLuceneQueryFieldNoBoost(string fieldName, BasicQueryFactory qf)
+ {
+ return MakeLuceneQueryNoBoost(qf); /* use this.fieldNames instead of fieldName */
+ }
+
+ public virtual IEnumerable<string> FieldNames { get { return fieldNames; } }
+
+ public virtual char FieldOperator { get { return fieldOp; } }
+
+ public override string ToString()
+ {
+ StringBuilder r = new StringBuilder();
+ r.Append("(");
+ FieldNamesToString(r);
+ r.Append(q.ToString());
+ r.Append(")");
+ return r.ToString();
+ }
+
+ protected virtual void FieldNamesToString(StringBuilder r)
+ {
+ foreach (var fieldName in FieldNames)
+ {
+ r.Append(fieldName);
+ r.Append(FieldOperator);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/679ad24c/src/Lucene.Net.QueryParser/Surround/Query/NotQuery.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Surround/Query/NotQuery.cs b/src/Lucene.Net.QueryParser/Surround/Query/NotQuery.cs
new file mode 100644
index 0000000..30d40a8
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Surround/Query/NotQuery.cs
@@ -0,0 +1,48 @@
+\ufeffusing Lucene.Net.Search;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Lucene.Net.QueryParser.Surround.Query
+{
+ /*
+ * 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.
+ */
+
+ /// <summary>
+ /// Factory for prohibited clauses
+ /// </summary>
+ public class NotQuery : ComposedQuery
+ {
+ public NotQuery(IEnumerable<SrndQuery> queries, string opName)
+ : base(queries, true /* infix */, opName)
+ {
+ }
+
+ public override Search.Query MakeLuceneQueryFieldNoBoost(string fieldName, BasicQueryFactory qf)
+ {
+ var luceneSubQueries = MakeLuceneSubQueriesField(fieldName, qf);
+ BooleanQuery bq = new BooleanQuery();
+ bq.Add(luceneSubQueries.FirstOrDefault(), BooleanClause.Occur.MUST);
+ SrndBooleanQuery.AddQueriesToBoolean(bq,
+ // FIXME: do not allow weights on prohibited subqueries.
+ //luceneSubQueries.subList(1, luceneSubQueries.size()),
+ luceneSubQueries.Skip(1).ToList(),
+ // later subqueries: not required, prohibited
+ BooleanClause.Occur.MUST_NOT);
+ return bq;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/679ad24c/src/Lucene.Net.QueryParser/Surround/Query/OrQuery.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Surround/Query/OrQuery.cs b/src/Lucene.Net.QueryParser/Surround/Query/OrQuery.cs
new file mode 100644
index 0000000..f7d0036
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Surround/Query/OrQuery.cs
@@ -0,0 +1,71 @@
+\ufeffusing Lucene.Net.Search;
+using System.Collections.Generic;
+
+namespace Lucene.Net.QueryParser.Surround.Query
+{
+ /*
+ * 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.
+ */
+
+ /// <summary>
+ /// Factory for disjunctions
+ /// </summary>
+ public class OrQuery : ComposedQuery, IDistanceSubQuery
+ {
+ public OrQuery(IEnumerable<SrndQuery> queries, bool infix, string opName)
+ : base(queries, infix, opName)
+ {
+ }
+
+ public override Search.Query MakeLuceneQueryFieldNoBoost(string fieldName, BasicQueryFactory qf)
+ {
+ return SrndBooleanQuery.MakeBooleanQuery(
+ /* subqueries can be individually boosted */
+ MakeLuceneSubQueriesField(fieldName, qf), BooleanClause.Occur.SHOULD);
+ }
+
+ public virtual string DistanceSubQueryNotAllowed()
+ {
+ var sqi = GetSubQueriesEnumerator();
+ while (sqi.MoveNext())
+ {
+ SrndQuery leq = sqi.Current;
+ if (leq is IDistanceSubQuery)
+ {
+ string m = ((IDistanceSubQuery)leq).DistanceSubQueryNotAllowed();
+ if (m != null)
+ {
+ return m;
+ }
+ }
+ else
+ {
+ return "subquery not allowed: " + leq.ToString();
+ }
+ }
+ return null;
+ }
+
+ public virtual void AddSpanQueries(SpanNearClauseFactory sncf)
+ {
+ var sqi = GetSubQueriesEnumerator();
+ while (sqi.MoveNext())
+ {
+ ((IDistanceSubQuery)sqi.Current).AddSpanQueries(sncf);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/679ad24c/src/Lucene.Net.QueryParser/Surround/Query/RewriteQuery.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Surround/Query/RewriteQuery.cs b/src/Lucene.Net.QueryParser/Surround/Query/RewriteQuery.cs
new file mode 100644
index 0000000..030923f
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Surround/Query/RewriteQuery.cs
@@ -0,0 +1,85 @@
+\ufeffusing Lucene.Net.Index;
+using System;
+
+namespace Lucene.Net.QueryParser.Surround.Query
+{
+ /*
+ * 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.
+ */
+
+ public abstract class RewriteQuery<SQ> : Search.Query
+ {
+ protected readonly SQ srndQuery;
+ protected readonly string fieldName;
+ protected readonly BasicQueryFactory qf;
+
+ public RewriteQuery(
+ SQ srndQuery,
+ String fieldName,
+ BasicQueryFactory qf)
+ {
+ this.srndQuery = srndQuery;
+ this.fieldName = fieldName;
+ this.qf = qf;
+ }
+
+ public abstract override Search.Query Rewrite(IndexReader reader);
+
+ public override string ToString()
+ {
+ return ToString(null);
+ }
+
+ public override string ToString(string field)
+ {
+ return GetType().Name
+ + (field == null ? "" : "(unused: " + field + ")")
+ + "(" + fieldName
+ + ", " + srndQuery.ToString()
+ + ", " + qf.ToString()
+ + ")";
+ }
+
+ public override int GetHashCode()
+ {
+ return GetType().GetHashCode()
+ ^ fieldName.GetHashCode()
+ ^ qf.GetHashCode()
+ ^ srndQuery.GetHashCode();
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null)
+ return false;
+ if (!GetType().Equals(obj.GetType()))
+ return false;
+ RewriteQuery<SQ> other = (RewriteQuery<SQ>)obj;
+ return fieldName.Equals(other.fieldName)
+ && qf.Equals(other.qf)
+ && srndQuery.Equals(other.srndQuery);
+ }
+
+ /// <summary>
+ /// Not supported by this query.
+ /// </summary>
+ /// <exception cref="NotSupportedException">throws NotSupportedException always: clone is not supported.</exception>
+ public override object Clone()
+ {
+ throw new NotSupportedException();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/679ad24c/src/Lucene.Net.QueryParser/Surround/Query/SimpleTerm.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Surround/Query/SimpleTerm.cs b/src/Lucene.Net.QueryParser/Surround/Query/SimpleTerm.cs
new file mode 100644
index 0000000..5e39e03
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Surround/Query/SimpleTerm.cs
@@ -0,0 +1,118 @@
+\ufeffusing Lucene.Net.Index;
+using System;
+using System.Text;
+
+namespace Lucene.Net.QueryParser.Surround.Query
+{
+ /*
+ * 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.
+ */
+
+ /// <summary>
+ /// Base class for queries that expand to sets of simple terms.
+ /// </summary>
+ public abstract class SimpleTerm : SrndQuery, IDistanceSubQuery, IComparable<SimpleTerm>
+ {
+ public SimpleTerm(bool q)
+ {
+ quoted = q;
+ }
+
+ private bool quoted;
+ internal bool IsQuoted { get { return quoted; } }
+
+ public virtual string Quote { get { return "\""; }}
+ public virtual string FieldOperator { get { return "/"; } }
+
+ public abstract string ToStringUnquoted();
+
+ [Obsolete("deprecated (March 2011) Not normally used, to be removed from Lucene 4.0. This class implementing Comparable is to be removed at the same time.")]
+ public int CompareTo(SimpleTerm ost)
+ {
+ /* for ordering terms and prefixes before using an index, not used */
+ return this.ToStringUnquoted().CompareTo(ost.ToStringUnquoted());
+ }
+
+ protected virtual void SuffixToString(StringBuilder r) { } /* override for prefix query */
+
+
+ public override string ToString()
+ {
+ StringBuilder r = new StringBuilder();
+ if (IsQuoted)
+ {
+ r.Append(Quote);
+ }
+ r.Append(ToStringUnquoted());
+ if (IsQuoted)
+ {
+ r.Append(Quote);
+ }
+ SuffixToString(r);
+ WeightToString(r);
+ return r.ToString();
+ }
+
+ public abstract void VisitMatchingTerms(
+ IndexReader reader,
+ string fieldName,
+ IMatchingTermVisitor mtv);
+
+ /// <summary>
+ /// Callback to visit each matching term during "rewrite"
+ /// in <see cref="M:VisitMatchingTerm(Term)"/>
+ /// </summary>
+ public interface IMatchingTermVisitor
+ {
+ void VisitMatchingTerm(Term t);
+ }
+
+ public string DistanceSubQueryNotAllowed()
+ {
+ return null;
+ }
+
+ public void AddSpanQueries(SpanNearClauseFactory sncf)
+ {
+ VisitMatchingTerms(
+ sncf.IndexReader,
+ sncf.FieldName,
+ new AddSpanQueriesMatchingTermVisitor(sncf, Weight));
+ }
+
+ internal class AddSpanQueriesMatchingTermVisitor : IMatchingTermVisitor
+ {
+ private readonly SpanNearClauseFactory sncf;
+ private readonly float weight;
+
+ public AddSpanQueriesMatchingTermVisitor(SpanNearClauseFactory sncf, float weight)
+ {
+ this.sncf = sncf;
+ this.weight = weight;
+ }
+
+ public void VisitMatchingTerm(Term term)
+ {
+ sncf.AddTermWeighted(term, weight);
+ }
+ }
+
+ public override Search.Query MakeLuceneQueryFieldNoBoost(string fieldName, BasicQueryFactory qf)
+ {
+ return new SimpleTermRewriteQuery(this, fieldName, qf);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/679ad24c/src/Lucene.Net.QueryParser/Surround/Query/SimpleTermRewriteQuery.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Surround/Query/SimpleTermRewriteQuery.cs b/src/Lucene.Net.QueryParser/Surround/Query/SimpleTermRewriteQuery.cs
new file mode 100644
index 0000000..6502d6c
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Surround/Query/SimpleTermRewriteQuery.cs
@@ -0,0 +1,64 @@
+\ufeffusing Lucene.Net.Index;
+using Lucene.Net.Search;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Lucene.Net.QueryParser.Surround.Query
+{
+ /*
+ * 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.
+ */
+
+ internal class SimpleTermRewriteQuery : RewriteQuery<SimpleTerm>
+ {
+ public SimpleTermRewriteQuery(
+ SimpleTerm srndQuery,
+ string fieldName,
+ BasicQueryFactory qf)
+ : base(srndQuery, fieldName, qf)
+ {
+ }
+
+ public override Search.Query Rewrite(IndexReader reader)
+ {
+ var luceneSubQueries = new List<Search.Query>();
+ srndQuery.VisitMatchingTerms(reader, fieldName,
+ new SimpleTermRewriteMatchingTermVisitor(luceneSubQueries, qf));
+ return (luceneSubQueries.Count == 0) ? SrndQuery.TheEmptyLcnQuery
+ : (luceneSubQueries.Count == 1) ? luceneSubQueries.First()
+ : SrndBooleanQuery.MakeBooleanQuery(
+ /* luceneSubQueries all have default weight */
+ luceneSubQueries, BooleanClause.Occur.SHOULD); /* OR the subquery terms */
+ }
+
+ internal class SimpleTermRewriteMatchingTermVisitor : SimpleTerm.IMatchingTermVisitor
+ {
+ private readonly IList<Search.Query> luceneSubQueries;
+ private readonly BasicQueryFactory qf;
+
+ public SimpleTermRewriteMatchingTermVisitor(IList<Search.Query> luceneSubQueries, BasicQueryFactory qf)
+ {
+ this.luceneSubQueries = luceneSubQueries;
+ this.qf = qf;
+ }
+
+ public void VisitMatchingTerm(Term term)
+ {
+ luceneSubQueries.Add(qf.NewTermQuery(term));
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/679ad24c/src/Lucene.Net.QueryParser/Surround/Query/SpanNearClauseFactory.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Surround/Query/SpanNearClauseFactory.cs b/src/Lucene.Net.QueryParser/Surround/Query/SpanNearClauseFactory.cs
new file mode 100644
index 0000000..6cddb9c
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Surround/Query/SpanNearClauseFactory.cs
@@ -0,0 +1,93 @@
+\ufeffusing Lucene.Net.Index;
+using Lucene.Net.Search.Spans;
+using Lucene.Net.Support;
+using System;
+using System.Collections.Generic;
+
+namespace Lucene.Net.QueryParser.Surround.Query
+{
+ /*
+ * 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.
+ */
+
+ /// <summary>
+ /// Factory for <see cref="SpanOrQuery"/>
+ /// </summary>
+ public class SpanNearClauseFactory
+ {
+ public SpanNearClauseFactory(IndexReader reader, string fieldName, BasicQueryFactory qf) {
+ this.reader = reader;
+ this.fieldName = fieldName;
+ this.weightBySpanQuery = new HashMap<SpanQuery, float>();
+ this.qf = qf;
+ }
+
+ private IndexReader reader;
+ private string fieldName;
+ private IDictionary<SpanQuery, float> weightBySpanQuery;
+ private BasicQueryFactory qf;
+
+ public virtual IndexReader IndexReader { get { return reader; } }
+
+ public virtual string FieldName { get { return fieldName; } }
+
+ public virtual BasicQueryFactory BasicQueryFactory { get { return qf; } }
+
+ public virtual int Count { get { return weightBySpanQuery.Count; } }
+
+ public virtual void Clear() { weightBySpanQuery.Clear(); }
+
+ protected virtual void AddSpanQueryWeighted(SpanQuery sq, float weight)
+ {
+ float w;
+ if (weightBySpanQuery.ContainsKey(sq))
+ w = weightBySpanQuery[sq] + weight;
+ else
+ w = weight;
+ weightBySpanQuery[sq] = w;
+ }
+
+ public virtual void AddTermWeighted(Term t, float weight)
+ {
+ SpanTermQuery stq = qf.NewSpanTermQuery(t);
+ /* CHECKME: wrap in Hashable...? */
+ AddSpanQueryWeighted(stq, weight);
+ }
+
+ public virtual void AddSpanQuery(Search.Query q)
+ {
+ if (q == SrndQuery.TheEmptyLcnQuery)
+ return;
+ if (!(q is SpanQuery))
+ throw new InvalidOperationException("Expected SpanQuery: " + q.ToString(FieldName));
+ AddSpanQueryWeighted((SpanQuery)q, q.Boost);
+ }
+
+ public SpanQuery MakeSpanClause()
+ {
+ List<SpanQuery> spanQueries = new List<SpanQuery>();
+ foreach (var wsq in weightBySpanQuery)
+ {
+ wsq.Key.Boost = wsq.Value;
+ spanQueries.Add(wsq.Key);
+ }
+ if (spanQueries.Count == 1)
+ return spanQueries[0];
+ else
+ return new SpanOrQuery(spanQueries.ToArray());
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/679ad24c/src/Lucene.Net.QueryParser/Surround/Query/SrndBooleanQuery.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Surround/Query/SrndBooleanQuery.cs b/src/Lucene.Net.QueryParser/Surround/Query/SrndBooleanQuery.cs
new file mode 100644
index 0000000..7a1a8b3
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Surround/Query/SrndBooleanQuery.cs
@@ -0,0 +1,51 @@
+\ufeffusing Lucene.Net.Search;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Lucene.Net.QueryParser.Surround.Query
+{
+ /*
+ * 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.
+ */
+
+ public static class SrndBooleanQuery
+ {
+ public static void AddQueriesToBoolean(
+ BooleanQuery bq,
+ IEnumerable<Search.Query> queries,
+ BooleanClause.Occur occur)
+ {
+ foreach (var query in queries)
+ {
+ bq.Add(query, occur);
+ }
+ }
+
+ public static Search.Query MakeBooleanQuery(
+ IEnumerable<Search.Query> queries,
+ BooleanClause.Occur occur)
+ {
+ if (queries.Count() <= 1)
+ {
+ throw new InvalidOperationException("Too few subqueries: " + queries.Count());
+ }
+ BooleanQuery bq = new BooleanQuery();
+ AddQueriesToBoolean(bq, queries, occur);
+ return bq;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/679ad24c/src/Lucene.Net.QueryParser/Surround/Query/SrndPrefixQuery.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Surround/Query/SrndPrefixQuery.cs b/src/Lucene.Net.QueryParser/Surround/Query/SrndPrefixQuery.cs
new file mode 100644
index 0000000..4044b09
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Surround/Query/SrndPrefixQuery.cs
@@ -0,0 +1,108 @@
+\ufeffusing Lucene.Net.Index;
+using Lucene.Net.Util;
+using System.Text;
+
+namespace Lucene.Net.QueryParser.Surround.Query
+{
+ /*
+ * 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.
+ */
+
+ /// <summary>
+ /// Query that matches String prefixes
+ /// </summary>
+ public class SrndPrefixQuery : SimpleTerm
+ {
+ private readonly BytesRef prefixRef;
+ public SrndPrefixQuery(string prefix, bool quoted, char truncator)
+ : base(quoted)
+ {
+ this.prefix = prefix;
+ prefixRef = new BytesRef(prefix);
+ this.truncator = truncator;
+ }
+
+ private readonly string prefix;
+ public virtual string Prefix { get { return prefix; } }
+
+ private readonly char truncator;
+ public virtual char SuffixOperator { get { return truncator; } }
+
+ public virtual Term GetLucenePrefixTerm(string fieldName)
+ {
+ return new Term(fieldName, Prefix);
+ }
+
+ public override string ToStringUnquoted()
+ {
+ return Prefix;
+ }
+
+ protected override void SuffixToString(StringBuilder r)
+ {
+ r.Append(SuffixOperator);
+ }
+
+ public override void VisitMatchingTerms(IndexReader reader, string fieldName, IMatchingTermVisitor mtv)
+ {
+ /* inspired by PrefixQuery.rewrite(): */
+ Terms terms = MultiFields.GetTerms(reader, fieldName);
+ if (terms != null)
+ {
+ TermsEnum termsEnum = terms.Iterator(null);
+
+ bool skip = false;
+ TermsEnum.SeekStatus status = termsEnum.SeekCeil(new BytesRef(Prefix));
+ if (status == TermsEnum.SeekStatus.FOUND)
+ {
+ mtv.VisitMatchingTerm(GetLucenePrefixTerm(fieldName));
+ }
+ else if (status == TermsEnum.SeekStatus.NOT_FOUND)
+ {
+ if (StringHelper.StartsWith(termsEnum.Term(), prefixRef))
+ {
+ mtv.VisitMatchingTerm(new Term(fieldName, termsEnum.Term().Utf8ToString()));
+ }
+ else
+ {
+ skip = true;
+ }
+ }
+ else
+ {
+ // EOF
+ skip = true;
+ }
+
+ if (!skip)
+ {
+ while (true)
+ {
+ BytesRef text = termsEnum.Next();
+ if (text != null && StringHelper.StartsWith(text, prefixRef))
+ {
+ mtv.VisitMatchingTerm(new Term(fieldName, text.Utf8ToString()));
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/679ad24c/src/Lucene.Net.QueryParser/Surround/Query/SrndQuery.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Surround/Query/SrndQuery.cs b/src/Lucene.Net.QueryParser/Surround/Query/SrndQuery.cs
new file mode 100644
index 0000000..57b19cc
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Surround/Query/SrndQuery.cs
@@ -0,0 +1,149 @@
+\ufeffusing Lucene.Net.Search;
+using Lucene.Net.Support;
+using System;
+using System.Text;
+
+namespace Lucene.Net.QueryParser.Surround.Query
+{
+ /*
+ * 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.
+ */
+
+ /// <summary>
+ /// Lowest level base class for surround queries
+ /// </summary>
+ public abstract class SrndQuery : ICloneable
+ {
+ //public SrndQuery() { }
+
+ private float weight = (float)1.0;
+ private bool weighted = false;
+
+ public virtual bool IsWeighted { get { return weighted; } }
+
+ public virtual float Weight
+ {
+ get { return weight; }
+ set
+ {
+ weight = value; /* as parsed from the query text */
+ weighted = true;
+ }
+ }
+
+ public virtual string WeightString { get { return Number.ToString(Weight); } }
+
+ public virtual string WeightOperator { get { return "^"; } }
+
+
+ protected virtual void WeightToString(StringBuilder r)
+ {
+ /* append the weight part of a query */
+ if (IsWeighted)
+ {
+ r.Append(WeightOperator);
+ r.Append(WeightString);
+ }
+ }
+
+ public virtual Search.Query MakeLuceneQueryField(string fieldName, BasicQueryFactory qf)
+ {
+ Search.Query q = MakeLuceneQueryFieldNoBoost(fieldName, qf);
+ if (IsWeighted)
+ {
+ q.Boost=(Weight * q.Boost); /* weight may be at any level in a SrndQuery */
+ }
+ return q;
+ }
+
+ public abstract Search.Query MakeLuceneQueryFieldNoBoost(string fieldName, BasicQueryFactory qf);
+
+ /// <summary>
+ /// This method is used by <see cref="M:GetHashCode()"/> and <see cref="M:Equals(Object)"/>,
+ /// see LUCENE-2945.
+ /// </summary>
+ /// <returns></returns>
+ public abstract override string ToString();
+
+ public virtual bool IsFieldsSubQueryAcceptable { get { return true; } }
+
+ /// <summary> Shallow clone. Subclasses must override this if they
+ /// need to clone any members deeply,
+ /// </summary>
+ public virtual object Clone()
+ {
+ object clone = null;
+ try
+ {
+ clone = base.MemberwiseClone();
+ }
+ catch (Exception e)
+ {
+ throw new SystemException(e.Message, e); // shouldn't happen
+ }
+ return clone;
+ }
+
+ /// <summary>
+ /// For subclasses of <see cref="SrndQuery"/> within the package
+ /// {@link org.apache.lucene.queryparser.surround.query}
+ /// it is not necessary to override this method, <see cref="M:ToString()"/>
+ /// </summary>
+ public override int GetHashCode()
+ {
+ return GetType().GetHashCode() ^ ToString().GetHashCode();
+ }
+
+ /// <summary>
+ /// For subclasses of <see cref="SrndQuery"/> within the package
+ /// {@link org.apache.lucene.queryparser.surround.query}
+ /// it is not necessary to override this method,
+ /// @see #toString()
+ /// </summary>
+ /// <param name="obj"></param>
+ /// <returns></returns>
+ public override bool Equals(object obj)
+ {
+ if (obj == null)
+ return false;
+ if (!GetType().Equals(obj.GetType()))
+ return false;
+ return ToString().Equals(obj.ToString());
+ }
+
+ /// <summary> An empty Lucene query </summary>
+ public readonly static Search.Query TheEmptyLcnQuery = new EmptyLcnQuery(); /* no changes allowed */
+
+ internal sealed class EmptyLcnQuery : BooleanQuery
+ {
+ public override float Boost
+ {
+ get { return base.Boost; }
+ set { throw new NotSupportedException(); }
+ }
+
+ public override void Add(BooleanClause clause)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override void Add(Search.Query query, BooleanClause.Occur occur)
+ {
+ throw new NotSupportedException();
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/679ad24c/src/Lucene.Net.QueryParser/Surround/Query/SrndTermQuery.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Surround/Query/SrndTermQuery.cs b/src/Lucene.Net.QueryParser/Surround/Query/SrndTermQuery.cs
new file mode 100644
index 0000000..45885a1
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Surround/Query/SrndTermQuery.cs
@@ -0,0 +1,63 @@
+\ufeffusing Lucene.Net.Index;
+using Lucene.Net.Util;
+
+namespace Lucene.Net.QueryParser.Surround.Query
+{
+ /*
+ * 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.
+ */
+
+ /// <summary>
+ /// Simple single-term clause
+ /// </summary>
+ public class SrndTermQuery : SimpleTerm
+ {
+ public SrndTermQuery(string termText, bool quoted)
+ : base(quoted)
+ {
+ this.termText = termText;
+ }
+
+ private readonly string termText;
+ public virtual string TermText { get { return termText; } }
+
+ public virtual Term GetLuceneTerm(string fieldName)
+ {
+ return new Term(fieldName, TermText);
+ }
+
+ public override string ToStringUnquoted()
+ {
+ return TermText;
+ }
+
+ public override void VisitMatchingTerms(IndexReader reader, string fieldName, IMatchingTermVisitor mtv)
+ {
+ /* check term presence in index here for symmetry with other SimpleTerm's */
+ Terms terms = MultiFields.GetTerms(reader, fieldName);
+ if (terms != null)
+ {
+ TermsEnum termsEnum = terms.Iterator(null);
+
+ TermsEnum.SeekStatus status = termsEnum.SeekCeil(new BytesRef(TermText));
+ if (status == TermsEnum.SeekStatus.FOUND)
+ {
+ mtv.VisitMatchingTerm(GetLuceneTerm(fieldName));
+ }
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/679ad24c/src/Lucene.Net.QueryParser/Surround/Query/SrndTruncQuery.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Surround/Query/SrndTruncQuery.cs b/src/Lucene.Net.QueryParser/Surround/Query/SrndTruncQuery.cs
new file mode 100644
index 0000000..5ed9ff3
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Surround/Query/SrndTruncQuery.cs
@@ -0,0 +1,139 @@
+\ufeffusing Lucene.Net.Index;
+using Lucene.Net.Util;
+using System;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace Lucene.Net.QueryParser.Surround.Query
+{
+ /*
+ * 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.
+ */
+
+ public class SrndTruncQuery : SimpleTerm
+ {
+ public SrndTruncQuery(string truncated, char unlimited, char mask)
+ : base(false) /* not quoted */
+ {
+ this.truncated = truncated;
+ this.unlimited = unlimited;
+ this.mask = mask;
+ TruncatedToPrefixAndPattern();
+ }
+
+ private readonly string truncated;
+ private readonly char unlimited;
+ private readonly char mask;
+
+ private string prefix;
+ private BytesRef prefixRef;
+ private Regex pattern;
+
+ public virtual string Truncated { get { return truncated; } }
+
+ public override string ToStringUnquoted()
+ {
+ return Truncated;
+ }
+
+ protected virtual bool MatchingChar(char c)
+ {
+ return (c != unlimited) && (c != mask);
+ }
+
+ protected virtual void AppendRegExpForChar(char c, StringBuilder re)
+ {
+ if (c == unlimited)
+ re.Append(".*");
+ else if (c == mask)
+ re.Append(".");
+ else
+ re.Append(c);
+ }
+
+ protected virtual void TruncatedToPrefixAndPattern()
+ {
+ int i = 0;
+ while ((i < truncated.Length) && MatchingChar(truncated[i]))
+ {
+ i++;
+ }
+ prefix = truncated.Substring(0, i);
+ prefixRef = new BytesRef(prefix);
+
+ StringBuilder re = new StringBuilder();
+ while (i < truncated.Length)
+ {
+ AppendRegExpForChar(truncated[i], re);
+ i++;
+ }
+ pattern = new Regex(re.ToString(), RegexOptions.Compiled);
+ }
+
+ // TODO: Finish implementation
+ public override void VisitMatchingTerms(IndexReader reader, string fieldName, SimpleTerm.IMatchingTermVisitor mtv)
+ {
+ throw new NotImplementedException("Need to translate this from Java's whacky RegEx syntax");
+ //int prefixLength = prefix.Length;
+ //Terms terms = MultiFields.GetTerms(reader, fieldName);
+ //if (terms != null)
+ //{
+ // MatchCollection matcher = pattern.Matches("");
+ // try
+ // {
+ // TermsEnum termsEnum = terms.Iterator(null);
+
+ // TermsEnum.SeekStatus status = termsEnum.SeekCeil(prefixRef);
+ // BytesRef text;
+ // if (status == TermsEnum.SeekStatus.FOUND)
+ // {
+ // text = prefixRef;
+ // }
+ // else if (status == TermsEnum.SeekStatus.NOT_FOUND)
+ // {
+ // text = termsEnum.Term();
+ // }
+ // else
+ // {
+ // text = null;
+ // }
+
+ // while (text != null)
+ // {
+ // if (text != null && StringHelper.StartsWith(text, prefixRef))
+ // {
+ // string textString = text.Utf8ToString();
+ // matcher.Reset(textString.Substring(prefixLength));
+ // if (matcher.Success)
+ // {
+ // mtv.VisitMatchingTerm(new Term(fieldName, textString));
+ // }
+ // }
+ // else
+ // {
+ // break;
+ // }
+ // text = termsEnum.Next();
+ // }
+ // }
+ // finally
+ // {
+ // matcher.Reset();
+ // }
+ //}
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/679ad24c/src/Lucene.Net.QueryParser/Surround/Query/TooManyBasicQueries.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Surround/Query/TooManyBasicQueries.cs b/src/Lucene.Net.QueryParser/Surround/Query/TooManyBasicQueries.cs
new file mode 100644
index 0000000..27f313c
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Surround/Query/TooManyBasicQueries.cs
@@ -0,0 +1,30 @@
+\ufeffnamespace Lucene.Net.QueryParser.Surround.Query
+{
+ /*
+ * 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.
+ */
+
+ /// <summary>
+ /// Exception thrown when <see cref="BasicQueryFactory"/> would exceed the limit
+ /// of query clauses.
+ /// </summary>
+ public class TooManyBasicQueries : System.IO.IOException
+ {
+ public TooManyBasicQueries(int maxBasicQueries)
+ : base("Exceeded maximum of " + maxBasicQueries + " basic queries.")
+ { }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/679ad24c/src/Lucene.Net.Tests.QueryParser/Analyzing/TestAnalyzingQueryParser.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.QueryParser/Analyzing/TestAnalyzingQueryParser.cs b/src/Lucene.Net.Tests.QueryParser/Analyzing/TestAnalyzingQueryParser.cs
new file mode 100644
index 0000000..10756cf
--- /dev/null
+++ b/src/Lucene.Net.Tests.QueryParser/Analyzing/TestAnalyzingQueryParser.cs
@@ -0,0 +1,341 @@
+\ufeffusing System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Lucene.Net.Analysis;
+using Lucene.Net.Analysis.Tokenattributes;
+using Lucene.Net.Documents;
+using Lucene.Net.Index;
+using Lucene.Net.QueryParser.Classic;
+using Lucene.Net.Search;
+using Lucene.Net.Store;
+using Lucene.Net.Util;
+using NUnit.Framework;
+
+namespace Lucene.Net.QueryParser.Analyzing
+{
+ /*
+ * 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.
+ */
+
+ [TestFixture]
+ public class TestAnalyzingQueryParser : LuceneTestCase
+ {
+ private readonly static string FIELD = "field";
+
+ private Analyzer a;
+
+ private string[] wildcardInput;
+ private string[] wildcardExpected;
+ private string[] prefixInput;
+ private string[] prefixExpected;
+ private string[] rangeInput;
+ private string[] rangeExpected;
+ private string[] fuzzyInput;
+ private string[] fuzzyExpected;
+
+ private IDictionary<string, string> wildcardEscapeHits = new Dictionary<string, string>();
+ private IDictionary<string, string> wildcardEscapeMisses = new Dictionary<string, string>();
+
+ public override void SetUp()
+ {
+ base.SetUp();
+ wildcardInput = new string[] { "*bersetzung �ber*ung",
+ "M�tley Cr\u00fce M�tl?* Cr�?", "Ren�e Zellweger Ren?? Zellw?ger" };
+ wildcardExpected = new string[] { "*bersetzung uber*ung", "motley crue motl?* cru?",
+ "renee zellweger ren?? zellw?ger" };
+
+ prefixInput = new string[] { "�bersetzung �bersetz*",
+ "M�tley Cr�e M�tl* cr�*", "Ren�? Zellw*" };
+ prefixExpected = new string[] { "ubersetzung ubersetz*", "motley crue motl* cru*",
+ "rene? zellw*" };
+
+ rangeInput = new string[] { "[aa TO bb]", "{Ana�s TO Zo�}" };
+ rangeExpected = new string[] { "[aa TO bb]", "{anais TO zoe}" };
+
+ fuzzyInput = new string[] { "�bersetzung �bersetzung~0.9",
+ "M�tley Cr�e M�tley~0.75 Cr�e~0.5",
+ "Ren�e Zellweger Ren�e~0.9 Zellweger~" };
+ fuzzyExpected = new string[] { "ubersetzung ubersetzung~1",
+ "motley crue motley~1 crue~2", "renee zellweger renee~0 zellweger~2" };
+
+ wildcardEscapeHits["m�*tley"] = "moatley";
+
+ // need to have at least one genuine wildcard to trigger the wildcard analysis
+ // hence the * before the y
+ wildcardEscapeHits["m�\\*tl*y"] = "mo*tley";
+
+ // escaped backslash then true wildcard
+ wildcardEscapeHits["m�\\\\*tley"] = "mo\\atley";
+
+ // escaped wildcard then true wildcard
+ wildcardEscapeHits["m�\\??ley"] = "mo?tley";
+
+ // the first is an escaped * which should yield a miss
+ wildcardEscapeMisses["m�\\*tl*y"] = "moatley";
+
+ a = new ASCIIAnalyzer();
+ }
+
+ [Test]
+ public void TestSingleChunkExceptions()
+ {
+ bool ex = false;
+ string termStr = "the*tre";
+
+ Analyzer stopsAnalyzer = new MockAnalyzer
+ (Random(), MockTokenizer.WHITESPACE, true, MockTokenFilter.ENGLISH_STOPSET);
+ try
+ {
+ string q = ParseWithAnalyzingQueryParser(termStr, stopsAnalyzer, true);
+ }
+ catch (ParseException e)
+ {
+ if (e.Message.Contains("returned nothing"))
+ {
+ ex = true;
+ }
+ }
+ assertEquals("Should have returned nothing", true, ex);
+ ex = false;
+
+ AnalyzingQueryParser qp = new AnalyzingQueryParser(TEST_VERSION_CURRENT, FIELD, a);
+ try
+ {
+ qp.AnalyzeSingleChunk(FIELD, "", "not a single chunk");
+ }
+ catch (ParseException e)
+ {
+ if (e.Message.Contains("multiple terms"))
+ {
+ ex = true;
+ }
+ }
+ assertEquals("Should have produced multiple terms", true, ex);
+ }
+
+ [Test]
+ public void TestWildcardAlone()
+ {
+ //seems like crazy edge case, but can be useful in concordance
+ bool pex = false;
+ try
+ {
+ Query q = GetAnalyzedQuery("*", a, false);
+ }
+ catch (ParseException e)
+ {
+ pex = true;
+ }
+ assertEquals("Wildcard alone with allowWildcard=false", true, pex);
+
+ pex = false;
+ try
+ {
+ String qString = ParseWithAnalyzingQueryParser("*", a, true);
+ assertEquals("Every word", "*", qString);
+ }
+ catch (ParseException e)
+ {
+ pex = true;
+ }
+
+ assertEquals("Wildcard alone with allowWildcard=true", false, pex);
+ }
+
+ [Test]
+ public void TestWildCardEscapes()
+ {
+ foreach (var entry in wildcardEscapeHits)
+ {
+ Query q = GetAnalyzedQuery(entry.Key, a, false);
+ assertEquals("WildcardEscapeHits: " + entry.Key, true, IsAHit(q, entry.Value, a));
+ }
+ foreach (var entry in wildcardEscapeMisses)
+ {
+ Query q = GetAnalyzedQuery(entry.Key, a, false);
+ assertEquals("WildcardEscapeMisses: " + entry.Key, false, IsAHit(q, entry.Value, a));
+ }
+ }
+
+ [Test]
+ public void TestWildCardQueryNoLeadingAllowed()
+ {
+ bool ex = false;
+ try
+ {
+ string q = ParseWithAnalyzingQueryParser(wildcardInput[0], a, false);
+
+ }
+ catch (ParseException e)
+ {
+ ex = true;
+ }
+ assertEquals("Testing initial wildcard not allowed",
+ true, ex);
+ }
+
+ [Test]
+ public void TestWildCardQuery()
+ {
+ for (int i = 0; i < wildcardInput.Length; i++)
+ {
+ assertEquals("Testing wildcards with analyzer " + a.GetType() + ", input string: "
+ + wildcardInput[i], wildcardExpected[i], ParseWithAnalyzingQueryParser(wildcardInput[i], a, true));
+ }
+ }
+
+ [Test]
+ public void TestPrefixQuery()
+ {
+ for (int i = 0; i < prefixInput.Length; i++)
+ {
+ assertEquals("Testing prefixes with analyzer " + a.GetType() + ", input string: "
+ + prefixInput[i], prefixExpected[i], ParseWithAnalyzingQueryParser(prefixInput[i], a, false));
+ }
+ }
+
+ [Test]
+ public void TestRangeQuery()
+ {
+ for (int i = 0; i < rangeInput.Length; i++)
+ {
+ assertEquals("Testing ranges with analyzer " + a.GetType() + ", input string: "
+ + rangeInput[i], rangeExpected[i], ParseWithAnalyzingQueryParser(rangeInput[i], a, false));
+ }
+ }
+
+ [Test]
+ public void TestFuzzyQuery()
+ {
+ for (int i = 0; i < fuzzyInput.Length; i++)
+ {
+ assertEquals("Testing fuzzys with analyzer " + a.GetType() + ", input string: "
+ + fuzzyInput[i], fuzzyExpected[i], ParseWithAnalyzingQueryParser(fuzzyInput[i], a, false));
+ }
+ }
+
+
+ private string ParseWithAnalyzingQueryParser(string s, Analyzer a, bool allowLeadingWildcard)
+ {
+ Query q = GetAnalyzedQuery(s, a, allowLeadingWildcard);
+ return q.ToString(FIELD);
+ }
+
+ private Query GetAnalyzedQuery(string s, Analyzer a, bool allowLeadingWildcard)
+ {
+ AnalyzingQueryParser qp = new AnalyzingQueryParser(TEST_VERSION_CURRENT, FIELD, a);
+ qp.AllowLeadingWildcard = allowLeadingWildcard;
+ Query q = qp.Parse(s);
+ return q;
+ }
+
+ internal sealed class FoldingFilter : TokenFilter
+ {
+ private readonly ICharTermAttribute termAtt;
+
+ public FoldingFilter(TokenStream input)
+ : base(input)
+ {
+ termAtt = AddAttribute<ICharTermAttribute>();
+ }
+
+ public sealed override bool IncrementToken()
+ {
+ if (input.IncrementToken())
+ {
+ char[] term = termAtt.Buffer();
+ for (int i = 0; i < term.Length; i++)
+ switch (term[i])
+ {
+ case '�':
+ term[i] = 'u';
+ break;
+ case '�':
+ term[i] = 'o';
+ break;
+ case '�':
+ term[i] = 'e';
+ break;
+ case '�':
+ term[i] = 'i';
+ break;
+ }
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+
+ internal sealed class ASCIIAnalyzer : Analyzer
+ {
+
+ public override TokenStreamComponents CreateComponents(string fieldName, System.IO.TextReader reader)
+ {
+ Tokenizer result = new MockTokenizer(reader, MockTokenizer.WHITESPACE, true);
+ return new TokenStreamComponents(result, new FoldingFilter(result));
+ }
+ }
+
+ // LUCENE-4176
+ [Test]
+ public void TestByteTerms()
+ {
+ string s = "\u0e40\u0e02";
+ Analyzer analyzer = new MockBytesAnalyzer();
+ Classic.QueryParser qp = new AnalyzingQueryParser(TEST_VERSION_CURRENT, FIELD, analyzer);
+ Query q = qp.Parse("[\u0e40\u0e02 TO \u0e40\u0e02]");
+ assertEquals(true, IsAHit(q, s, analyzer));
+ }
+
+ private bool IsAHit(Query q, string content, Analyzer analyzer)
+ {
+ int hits;
+ using (Directory ramDir = NewDirectory())
+ {
+ using (RandomIndexWriter writer = new RandomIndexWriter(Random(), ramDir, analyzer))
+ {
+ Document doc = new Document();
+ FieldType fieldType = new FieldType();
+ fieldType.Indexed = (true);
+ fieldType.Tokenized = (true);
+ fieldType.Stored = (true);
+ Field field = new Field(FIELD, content, fieldType);
+ doc.Add(field);
+ writer.AddDocument(doc);
+ }
+ using (DirectoryReader ir = DirectoryReader.Open(ramDir))
+ {
+ IndexSearcher @is = new IndexSearcher(ir);
+
+ hits = @is.Search(q, 10).TotalHits;
+ }
+ }
+ if (hits == 1)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/679ad24c/src/Lucene.Net.Tests.QueryParser/Classic/TestMultiAnalyzer.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.QueryParser/Classic/TestMultiAnalyzer.cs b/src/Lucene.Net.Tests.QueryParser/Classic/TestMultiAnalyzer.cs
new file mode 100644
index 0000000..350f181
--- /dev/null
+++ b/src/Lucene.Net.Tests.QueryParser/Classic/TestMultiAnalyzer.cs
@@ -0,0 +1,278 @@
+\ufeffusing System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using NUnit.Framework;
+using Lucene.Net.Analysis;
+using Lucene.Net.Analysis.Tokenattributes;
+using Lucene.Net.Search;
+using Lucene.Net.Util;
+
+namespace Lucene.Net.QueryParser.Classic
+{
+ [TestFixture]
+ public class TestMultiAnalyzer_ : BaseTokenStreamTestCase
+ {
+
+ private static int multiToken = 0;
+
+ [Test]
+ public void TestMultiAnalyzer()
+ {
+
+ QueryParser qp = new QueryParser(TEST_VERSION_CURRENT, "", new MultiAnalyzer());
+
+ // trivial, no multiple tokens:
+ assertEquals("foo", qp.Parse("foo").toString());
+ assertEquals("foo", qp.Parse("\"foo\"").toString());
+ assertEquals("foo foobar", qp.Parse("foo foobar").toString());
+ assertEquals("\"foo foobar\"", qp.Parse("\"foo foobar\"").toString());
+ assertEquals("\"foo foobar blah\"", qp.Parse("\"foo foobar blah\"").toString());
+
+ // two tokens at the same position:
+ assertEquals("(multi multi2) foo", qp.Parse("multi foo").toString());
+ assertEquals("foo (multi multi2)", qp.Parse("foo multi").toString());
+ assertEquals("(multi multi2) (multi multi2)", qp.Parse("multi multi").toString());
+ assertEquals("+(foo (multi multi2)) +(bar (multi multi2))",
+ qp.Parse("+(foo multi) +(bar multi)").toString());
+ assertEquals("+(foo (multi multi2)) field:\"bar (multi multi2)\"",
+ qp.Parse("+(foo multi) field:\"bar multi\"").toString());
+
+ // phrases:
+ assertEquals("\"(multi multi2) foo\"", qp.Parse("\"multi foo\"").toString());
+ assertEquals("\"foo (multi multi2)\"", qp.Parse("\"foo multi\"").toString());
+ assertEquals("\"foo (multi multi2) foobar (multi multi2)\"",
+ qp.Parse("\"foo multi foobar multi\"").toString());
+
+ // fields:
+ assertEquals("(field:multi field:multi2) field:foo", qp.Parse("field:multi field:foo").toString());
+ assertEquals("field:\"(multi multi2) foo\"", qp.Parse("field:\"multi foo\"").toString());
+
+ // three tokens at one position:
+ assertEquals("triplemulti multi3 multi2", qp.Parse("triplemulti").toString());
+ assertEquals("foo (triplemulti multi3 multi2) foobar",
+ qp.Parse("foo triplemulti foobar").toString());
+
+ // phrase with non-default slop:
+ assertEquals("\"(multi multi2) foo\"~10", qp.Parse("\"multi foo\"~10").toString());
+
+ // phrase with non-default boost:
+ assertEquals("\"(multi multi2) foo\"^2.0", qp.Parse("\"multi foo\"^2").toString());
+
+ // phrase after changing default slop
+ qp.PhraseSlop=(99);
+ assertEquals("\"(multi multi2) foo\"~99 bar",
+ qp.Parse("\"multi foo\" bar").toString());
+ assertEquals("\"(multi multi2) foo\"~99 \"foo bar\"~2",
+ qp.Parse("\"multi foo\" \"foo bar\"~2").toString());
+ qp.PhraseSlop=(0);
+
+ // non-default operator:
+ qp.DefaultOperator=(QueryParserBase.AND_OPERATOR);
+ assertEquals("+(multi multi2) +foo", qp.Parse("multi foo").toString());
+
+ }
+
+ [Test]
+ public void TestMultiAnalyzerWithSubclassOfQueryParser()
+ {
+
+ DumbQueryParser qp = new DumbQueryParser("", new MultiAnalyzer());
+ qp.PhraseSlop = (99); // modified default slop
+
+ // direct call to (super's) getFieldQuery to demonstrate differnce
+ // between phrase and multiphrase with modified default slop
+ assertEquals("\"foo bar\"~99",
+ qp.GetSuperFieldQuery("", "foo bar", true).toString());
+ assertEquals("\"(multi multi2) bar\"~99",
+ qp.GetSuperFieldQuery("", "multi bar", true).toString());
+
+
+ // ask sublcass to parse phrase with modified default slop
+ assertEquals("\"(multi multi2) foo\"~99 bar",
+ qp.Parse("\"multi foo\" bar").toString());
+
+ }
+
+ [Test]
+ public void TestPosIncrementAnalyzer()
+ {
+ QueryParser qp = new QueryParser(LuceneVersion.LUCENE_40, "", new PosIncrementAnalyzer());
+ assertEquals("quick brown", qp.Parse("the quick brown").toString());
+ assertEquals("quick brown fox", qp.Parse("the quick brown fox").toString());
+ }
+
+ /// <summary>
+ /// Expands "multi" to "multi" and "multi2", both at the same position,
+ /// and expands "triplemulti" to "triplemulti", "multi3", and "multi2".
+ /// </summary>
+ private class MultiAnalyzer : Analyzer
+ {
+ public override TokenStreamComponents CreateComponents(string fieldName, System.IO.TextReader reader)
+ {
+ Tokenizer result = new MockTokenizer(reader, MockTokenizer.WHITESPACE, true);
+ return new TokenStreamComponents(result, new TestFilter(result));
+ }
+ }
+
+ private sealed class TestFilter : TokenFilter
+ {
+
+ private string prevType;
+ private int prevStartOffset;
+ private int prevEndOffset;
+
+ private readonly ICharTermAttribute termAtt;
+ private readonly IPositionIncrementAttribute posIncrAtt;
+ private readonly IOffsetAttribute offsetAtt;
+ private readonly ITypeAttribute typeAtt;
+
+ public TestFilter(TokenStream @in)
+ : base(@in)
+ {
+ termAtt = AddAttribute<ICharTermAttribute>();
+ posIncrAtt = AddAttribute<IPositionIncrementAttribute>();
+ offsetAtt = AddAttribute<IOffsetAttribute>();
+ typeAtt = AddAttribute<ITypeAttribute>();
+ }
+
+ public override sealed bool IncrementToken()
+ {
+ if (multiToken > 0)
+ {
+ termAtt.SetEmpty().Append("multi" + (multiToken + 1));
+ offsetAtt.SetOffset(prevStartOffset, prevEndOffset);
+ typeAtt.Type = (prevType);
+ posIncrAtt.PositionIncrement = (0);
+ multiToken--;
+ return true;
+ }
+ else
+ {
+ bool next = input.IncrementToken();
+ if (!next)
+ {
+ return false;
+ }
+ prevType = typeAtt.Type;
+ prevStartOffset = offsetAtt.StartOffset();
+ prevEndOffset = offsetAtt.EndOffset();
+ string text = termAtt.toString();
+ if (text.equals("triplemulti"))
+ {
+ multiToken = 2;
+ return true;
+ }
+ else if (text.equals("multi"))
+ {
+ multiToken = 1;
+ return true;
+ }
+ else
+ {
+ return true;
+ }
+ }
+ }
+
+ public override void Reset()
+ {
+ base.Reset();
+ this.prevType = null;
+ this.prevStartOffset = 0;
+ this.prevEndOffset = 0;
+ }
+ }
+
+ /// <summary>
+ /// Analyzes "the quick brown" as: quick(incr=2) brown(incr=1).
+ /// Does not work correctly for input other than "the quick brown ...".
+ /// </summary>
+ private class PosIncrementAnalyzer : Analyzer
+ {
+ public override TokenStreamComponents CreateComponents(string fieldName, System.IO.TextReader reader)
+ {
+ Tokenizer result = new MockTokenizer(reader, MockTokenizer.WHITESPACE, true);
+ return new TokenStreamComponents(result, new TestPosIncrementFilter(result));
+ }
+ }
+
+ private sealed class TestPosIncrementFilter : TokenFilter
+ {
+ ICharTermAttribute termAtt;
+ IPositionIncrementAttribute posIncrAtt;
+
+ public TestPosIncrementFilter(TokenStream @in)
+ : base(@in)
+ {
+ termAtt = AddAttribute<ICharTermAttribute>();
+ posIncrAtt = AddAttribute<IPositionIncrementAttribute>();
+ }
+
+ public override sealed bool IncrementToken()
+ {
+ while (input.IncrementToken())
+ {
+ if (termAtt.toString().equals("the"))
+ {
+ // stopword, do nothing
+ }
+ else if (termAtt.toString().equals("quick"))
+ {
+ posIncrAtt.PositionIncrement = (2);
+ return true;
+ }
+ else
+ {
+ posIncrAtt.PositionIncrement = (1);
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// a very simple subclass of QueryParser
+ /// </summary>
+ private sealed class DumbQueryParser : QueryParser
+ {
+ public DumbQueryParser(string f, Analyzer a)
+ : base(TEST_VERSION_CURRENT, f, a)
+ {
+ }
+
+ // expose super's version
+ public Query GetSuperFieldQuery(string f, string t, bool quoted)
+ {
+ return base.GetFieldQuery(f, t, quoted);
+ }
+
+ // wrap super's version
+ protected internal override Query GetFieldQuery(string field, string queryText, bool quoted)
+ {
+ return new DumbQueryWrapper(GetSuperFieldQuery(field, queryText, quoted));
+ }
+ }
+
+ /// <summary>
+ /// A very simple wrapper to prevent instanceof checks but uses
+ /// the toString of the query it wraps.
+ /// </summary>
+ private sealed class DumbQueryWrapper : Query
+ {
+ private Query q;
+ public DumbQueryWrapper(Query q)
+ {
+ this.q = q;
+ }
+
+ public override string ToString(string field)
+ {
+ return q.ToString(field);
+ }
+ }
+
+ }
+}