So I've taken my first shot at solving my problem using the three functions below.
When I set the slop to 10 it produces the following result: This BooleanQuery +content:"london olympics" +(+content:football +content:or +content:soccer) -content:nfl becomes this SpanQuery: spanNot(spanNear([spanNear([content:london, content:olympics], 0, true), spanNear([content:football, content:or, content:soccer], 10, false)], 10, false), spanOr([content:nfl])) Right now I've implemented TermQuery, PhraseQuery and BooleanQuery. Is there a list of queries that could be produced using the Lucene Query Parser? Any thoughts on how I should implement Wildcard queries? Thanks! -Dave public static SpanQuery ConvertQuery(Query input, int slop) { SpanQuery convertedQuery = null; if(input instanceof TermQuery) { //support for term query convertedQuery = new SpanTermQuery(((TermQuery)input).getTerm()); } else if(input instanceof PhraseQuery) { //support for phrase query convertedQuery = ConvertPhraseQueryToSpanQuery((PhraseQuery)input); } else if(input instanceof BooleanQuery) { //support for nested boolean query convertedQuery = ConvertBooleanQuery((BooleanQuery)input,slop); } return convertedQuery; } public static SpanQuery ConvertPhraseQueryToSpanQuery(PhraseQuery input) { SpanQuery retval = null; ArrayList<SpanQuery> terms = new ArrayList<SpanQuery>(); for(Term t : input.getTerms()) { terms.add(new SpanTermQuery(t)); } retval = new SpanNearQuery(terms.toArray(new SpanQuery[terms.size()]), 0, true); return retval; } public static SpanQuery ConvertBooleanQuery(BooleanQuery input, int slop) { ArrayList<SpanQuery> andClauses = new ArrayList<SpanQuery>(); ArrayList<SpanQuery> orClauses = new ArrayList<SpanQuery>(); ArrayList<SpanQuery> notClauses = new ArrayList<SpanQuery>(); SpanQuery retval = null; //iterate thorough any child clauses prior to for(BooleanClause clause : ((BooleanQuery) input).clauses()) { SpanQuery convertedQuery = ConvertQuery(clause.getQuery(), slop); if(convertedQuery != null) { if(clause.getOccur() == BooleanClause.Occur.MUST) { andClauses.add(convertedQuery); } else if (clause.getOccur() == BooleanClause.Occur.SHOULD) { orClauses.add(convertedQuery); } else if (clause.getOccur() == BooleanClause.Occur.MUST_NOT) { notClauses.add(convertedQuery); } } } //alright, now lets assemble the clauses that we've collected for this query SpanQuery andSpans = null; SpanQuery orSpans = null; SpanQuery notSpans = null; //if there are no ANDs and no ORs then we'll return null if(andClauses.size() + orClauses.size() == 0) return null; if(andClauses.size() > 0) { if(andClauses.size() > 1) { andSpans = new SpanNearQuery(andClauses.toArray(new SpanQuery[andClauses.size()]), slop, false); } else { andSpans = andClauses.get(0); } } if(orClauses.size() > 0) { orSpans = new SpanOrQuery(orClauses.toArray(new SpanQuery[orClauses.size()])); } if(notClauses.size() > 0) { notSpans = new SpanOrQuery(notClauses.toArray(new SpanQuery[notClauses.size()])); } //build an intermediate query using the above clauses SpanQuery intermediateQuery = null; if(andClauses.size() > 0 && orClauses.size() == 0) { intermediateQuery = andSpans; } else if (orClauses.size() > 0 && andClauses.size() == 0) { intermediateQuery = orSpans; } else { intermediateQuery = new SpanNearQuery(new SpanQuery[]{andSpans,orSpans}, slop, false); } //if we have any NOT queries append them to the end if(notClauses.size() > 0) { retval = new SpanNotQuery(intermediateQuery, notSpans); } else { retval = intermediateQuery; } return retval; }