title: Weird results with Solr 1.4 and EdgeNGrams - some substrings match, some don't
body: <p><strong>EDIT 3</strong>:  The workaround I'm using right now is to strip anything but letters, digits, and whitespace from both my queries and my indexed fields.  This produces the desired behavior, but it's very much a workaround rather than a true solution, and I would still like to understand why Solr is doing what it's doing...so still interested in an answer, if anyone has one. <strong>END EDIT 3</strong></p>
  
  <p>I have a document named "TT-14B" indexed by Solr 1.4 (via Django/Haystack).  When I query the <code>content_auto</code> field for "tt-1" or "tt 14" or "tt 14b" I get the document back; when I query "tt-14" or "tt-14b" I get no results.  I edited the Haystack-generated Solr schema a bit to try to fix this, to no avail.  Using analyze.jsp, it seems to me that I should be getting a match for "tt-14"; I should certainly be getting one for "tt-14b".  (<strong>Edit</strong>: Oh, and changing the default operator from AND to OR doesn't help.)</p>
  
  <p>Can someone help me understand why this isn't working?  Thanks.</p>
  
  <p>...</p>
  
  <p>results</p>
  
  <pre><code>QUERY  | WORKS
  =======|======
  tt     | yes
  tt-    | yes
  tt-1   | yes
  tt-14  | no
  tt-14b | no
  tt 14  | yes
  tt 14b | yes
  </code></pre>
  
  <p><strong>EDIT 2</strong></p>
  
  <p>Got some more comparably weird  results, might help debug the problem.  In this case the test document was "abc'def".</p>
  
  <pre><code>QUERY   | WORKS
  ========|======
  abc     | yes
  abc'd   | yes
  abc'de  | no
  abc'def | no
  </code></pre>
  
  <p>Same pattern, obviously, but I don't understand what's causing it.</p>
  
  <p><strong>END EDIT 2</strong></p>
  
  <p>schema.xml relevant part (full file below)</p>
  
  <pre><code>&lt;fieldType name="edge_ngram" class="solr.TextField" positionIncrementGap="1"&gt;
    &lt;analyzer type="index"&gt;
      &lt;tokenizer class="solr.WhitespaceTokenizerFactory" /&gt;
      &lt;filter class="solr.LowerCaseFilterFactory" /&gt;
      &lt;filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" splitOnNumerics="0" preserveOriginal="1" catenateWords="0" catenateNumbers="0" catenateAll="0" splitOnCaseChange="1"/&gt;
      &lt;filter class="solr.EdgeNGramFilterFactory" minGramSize="1" maxGramSize="15" side="front" /&gt;
    &lt;/analyzer&gt;
    &lt;analyzer type="query"&gt;
      &lt;tokenizer class="solr.WhitespaceTokenizerFactory" /&gt;
      &lt;filter class="solr.LowerCaseFilterFactory" /&gt;
      &lt;filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" splitOnNumerics="0" preserveOriginal="1" catenateWords="0" catenateNumbers="0" catenateAll="0" splitOnCaseChange="1"/&gt;
    &lt;/analyzer&gt;
  &lt;/fieldType&gt;
  </code></pre>
  
  <p>schema.xml (full)</p>
  
  <pre><code>&lt;?xml version="1.0" ?&gt;
  &lt;!--
   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.
  --&gt;
  
  &lt;schema name="default" version="1.1"&gt;
    &lt;types&gt;
      &lt;fieldtype name="string"  class="solr.StrField" sortMissingLast="true" omitNorms="true"/&gt;
      &lt;fieldType name="boolean" class="solr.BoolField" sortMissingLast="true" omitNorms="true"/&gt;
  
      &lt;!-- Numeric field types that manipulate the value into
           a string value that isn't human-readable in its internal form,
           but with a lexicographic ordering the same as the numeric ordering,
           so that range queries work correctly. --&gt;
      &lt;fieldType name="sint" class="solr.SortableIntField" sortMissingLast="true" omitNorms="true"/&gt;
      &lt;fieldType name="slong" class="solr.SortableLongField" sortMissingLast="true" omitNorms="true"/&gt;
      &lt;fieldType name="sfloat" class="solr.SortableFloatField" sortMissingLast="true" omitNorms="true"/&gt;
      &lt;fieldType name="sdouble" class="solr.SortableDoubleField" sortMissingLast="true" omitNorms="true"/&gt;
  
      &lt;fieldType name="date" class="solr.DateField" sortMissingLast="true" omitNorms="true"/&gt;
  
      &lt;fieldType name="text" class="solr.TextField" positionIncrementGap="100"&gt;
        &lt;analyzer type="index"&gt;
          &lt;tokenizer class="solr.WhitespaceTokenizerFactory"/&gt;
          &lt;!-- in this example, we will only use synonyms at query time
          &lt;filter class="solr.SynonymFilterFactory" synonyms="index_synonyms.txt" ignoreCase="true" expand="false"/&gt;
          --&gt;
          &lt;filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt"/&gt;
          &lt;filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" splitOnNumerics="0" preserveOriginal="1" catenateWords="1" catenateNumbers="1" catenateAll="1"/&gt;
          &lt;filter class="solr.LowerCaseFilterFactory"/&gt;
          &lt;filter class="solr.EnglishPorterFilterFactory" protected="protwords.txt"/&gt;
          &lt;filter class="solr.RemoveDuplicatesTokenFilterFactory"/&gt;
        &lt;/analyzer&gt;
        &lt;analyzer type="query"&gt;
          &lt;tokenizer class="solr.WhitespaceTokenizerFactory"/&gt;
          &lt;filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/&gt;
          &lt;filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt"/&gt;
          &lt;filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" splitOnNumerics="0" preserveOriginal="1" catenateWords="0" catenateNumbers="0" catenateAll="1"/&gt;
          &lt;filter class="solr.LowerCaseFilterFactory"/&gt;
          &lt;filter class="solr.EnglishPorterFilterFactory" protected="protwords.txt"/&gt;
          &lt;filter class="solr.RemoveDuplicatesTokenFilterFactory"/&gt;
        &lt;/analyzer&gt;
      &lt;/fieldType&gt;
  
      &lt;fieldType name="text_ws" class="solr.TextField" positionIncrementGap="100"&gt;
        &lt;analyzer&gt;
          &lt;tokenizer class="solr.WhitespaceTokenizerFactory"/&gt;
        &lt;/analyzer&gt;
      &lt;/fieldType&gt;
  
      &lt;fieldType name="ngram" class="solr.TextField" &gt;
        &lt;analyzer type="index"&gt;
          &lt;tokenizer class="solr.KeywordTokenizerFactory"/&gt;
          &lt;filter class="solr.LowerCaseFilterFactory"/&gt;
          &lt;filter class="solr.NGramFilterFactory" minGramSize="2" maxGramSize="15" /&gt;
        &lt;/analyzer&gt;
        &lt;analyzer type="query"&gt;
          &lt;tokenizer class="solr.KeywordTokenizerFactory"/&gt;
          &lt;filter class="solr.LowerCaseFilterFactory"/&gt;
        &lt;/analyzer&gt;
      &lt;/fieldType&gt;
  
      &lt;fieldType name="edge_ngram" class="solr.TextField" positionIncrementGap="1"&gt;
        &lt;analyzer type="index"&gt;
          &lt;tokenizer class="solr.WhitespaceTokenizerFactory" /&gt;
          &lt;filter class="solr.LowerCaseFilterFactory" /&gt;
          &lt;filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" splitOnNumerics="0" preserveOriginal="1" catenateWords="0" catenateNumbers="0" catenateAll="0" splitOnCaseChange="1"/&gt;
          &lt;filter class="solr.EdgeNGramFilterFactory" minGramSize="1" maxGramSize="15" side="front" /&gt;
        &lt;/analyzer&gt;
        &lt;analyzer type="query"&gt;
          &lt;tokenizer class="solr.WhitespaceTokenizerFactory" /&gt;
          &lt;filter class="solr.LowerCaseFilterFactory" /&gt;
          &lt;filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" splitOnNumerics="0" preserveOriginal="1" catenateWords="0" catenateNumbers="0" catenateAll="0" splitOnCaseChange="1"/&gt;
        &lt;/analyzer&gt;
      &lt;/fieldType&gt;
    &lt;/types&gt;
  
    &lt;fields&gt;   
      &lt;!-- general --&gt;
      &lt;field name="id" type="string" indexed="true" stored="true" multiValued="false" required="true"/&gt;
      &lt;field name="django_ct" type="string" indexed="true" stored="true" multiValued="false" /&gt;
      &lt;field name="django_id" type="string" indexed="true" stored="true" multiValued="false" /&gt;
  
      &lt;dynamicField name="*_i"  type="sint"    indexed="true"  stored="true"/&gt;
      &lt;dynamicField name="*_s"  type="string"  indexed="true"  stored="true"/&gt;
      &lt;dynamicField name="*_l"  type="slong"   indexed="true"  stored="true"/&gt;
      &lt;dynamicField name="*_t"  type="text"    indexed="true"  stored="true"/&gt;
      &lt;dynamicField name="*_b"  type="boolean" indexed="true"  stored="true"/&gt;
      &lt;dynamicField name="*_f"  type="sfloat"  indexed="true"  stored="true"/&gt;
      &lt;dynamicField name="*_d"  type="sdouble" indexed="true"  stored="true"/&gt;
      &lt;dynamicField name="*_dt" type="date"    indexed="true"  stored="true"/&gt;
  
  
      &lt;field name="modelname_exact" type="string" indexed="true" stored="true" multiValued="false" /&gt;
  
      &lt;field name="modelname" type="text" indexed="true" stored="true" multiValued="false" /&gt;
  
      &lt;field name="name" type="text" indexed="true" stored="true" multiValued="false" /&gt;
  
      &lt;field name="text" type="text" indexed="true" stored="true" multiValued="false" /&gt;
  
      &lt;field name="name_exact" type="string" indexed="true" stored="true" multiValued="false" /&gt;
  
      &lt;field name="content_auto" type="edge_ngram" indexed="true" stored="true" multiValued="true" /&gt;
  
    &lt;/fields&gt;
  
    &lt;!-- field to use to determine and enforce document uniqueness. --&gt;
    &lt;uniqueKey&gt;id&lt;/uniqueKey&gt;
  
    &lt;!-- field for the QueryParser to use when an explicit fieldname is absent --&gt;
    &lt;defaultSearchField&gt;text&lt;/defaultSearchField&gt;
  
    &lt;!-- SolrQueryParser configuration: defaultOperator="AND|OR" --&gt;
    &lt;solrQueryParser defaultOperator="AND" /&gt;
  &lt;/schema&gt;
  </code></pre>