Example usage for org.apache.lucene.search.spell SpellChecker suggestSimilar

List of usage examples for org.apache.lucene.search.spell SpellChecker suggestSimilar

Introduction

In this page you can find the example usage for org.apache.lucene.search.spell SpellChecker suggestSimilar.

Prototype

public String[] suggestSimilar(String word, int numSug) throws IOException 

Source Link

Document

Suggest similar words.

Usage

From source file:aos.lucene.tools.SpellCheckerExample.java

License:Apache License

public static void main(String[] args) throws IOException {

    if (args.length != 2) {
        LOGGER.info("Usage: java lia.tools.SpellCheckerTest SpellCheckerIndexDir wordToRespell");
        System.exit(1);// w  w w.  j a  va  2s.c o  m
    }

    String spellCheckDir = args[0];
    String wordToRespell = args[1];

    Directory dir = FSDirectory.open(new File(spellCheckDir));
    if (!IndexReader.indexExists(dir)) {
        LOGGER.info("\nERROR: No spellchecker index at path \"" + spellCheckDir
                + "\"; please run CreateSpellCheckerIndex first\n");
        System.exit(1);
    }
    SpellChecker spell = new SpellChecker(dir); // #A

    spell.setStringDistance(new LevensteinDistance()); // #B
    // spell.setStringDistance(new JaroWinklerDistance());

    String[] suggestions = spell.suggestSimilar(wordToRespell, 5); // #C
    LOGGER.info(suggestions.length + " suggestions for '" + wordToRespell + "':");
    for (String suggestion : suggestions)
        LOGGER.info("  " + suggestion);
}

From source file:com.bah.bahdit.main.plugins.fulltextindex.FullTextIndex.java

License:Apache License

/**
 * Performs levenshtein distance on each individual term in the search query.  
 * //www .j a va 2s  . c o  m
 * @param query - the query with no results
 * @param sampleTable - used to find the most popular correction
 * @param spellChecker- Lucene's spell checker
 * 
 * @return the best instance of a misspelled or not-found word.
 */
public static String fullTextLevDistance(String query, HashMap<String, Integer> sampleTable,
        SpellChecker spellChecker) {

    String bestResult = query;
    // look up every term individually
    for (String s : query.split(" ")) {

        // only account for words that don't appear in the sample table
        if (sampleTable.containsKey(s) || s.equals(""))
            continue;

        String[] suggestions;
        // get the best suggestions from Apache Lucene's spell check algorithm
        try {
            suggestions = spellChecker.suggestSimilar(s, NUM_SUGGESTIONS);
        } catch (IOException e) {
            return "";
        }

        // out of the given suggestions, find the most popular from the sample
        int max = 0;
        String popularStr = "";
        for (String result : suggestions) {
            Integer freq = sampleTable.get(result);
            if (freq != null && freq > max) {
                popularStr = result;
                max = freq;
            }
        }
        // replace bad terms with the new terms
        bestResult = bestResult.replaceAll(s, popularStr);
    }
    return bestResult;
}

From source file:com.jaeksoft.searchlib.spellcheck.SpellCheck.java

License:Open Source License

public SpellCheck(ReaderLocal reader, SpellCheckRequest request, SpellCheckField spellCheckField)
        throws ParseException, SyntaxError, IOException, SearchLibException {
    fieldName = spellCheckField.getName();
    SpellChecker spellchecker = reader.getSpellChecker(fieldName);
    Set<String> wordSet = new LinkedHashSet<String>();

    Set<Term> set = request.getTermSet(spellCheckField.getName());
    for (Term term : set)
        if (term.field().equals(fieldName))
            wordSet.add(term.text());//from   w w  w.  j a v  a2 s . c  om
    int suggestionNumber = spellCheckField.getSuggestionNumber();
    float minScore = spellCheckField.getMinScore();
    synchronized (spellchecker) {
        spellchecker.setAccuracy(minScore);
        spellchecker.setStringDistance(spellCheckField.getStringDistance().getNewInstance());
        spellCheckItems = new ArrayList<SpellCheckItem>();
        for (String word : wordSet) {
            String[] suggestions = spellchecker.suggestSimilar(word, suggestionNumber);
            int s = 1;
            if (suggestions != null)
                s += suggestions.length;
            SuggestionItem[] suggestionItems = new SuggestionItem[s];
            int i = 0;
            suggestionItems[i++] = new SuggestionItem(word);
            if (suggestions != null) {
                for (String suggestion : suggestions)
                    suggestionItems[i++] = new SuggestionItem(suggestion);
                spellCheckItems.add(new SpellCheckItem(word, suggestionItems));
            }
        }
    }
    List<String> highers = new ArrayList<String>(spellCheckItems.size());
    for (SpellCheckItem spellcheckItem : spellCheckItems) {
        spellcheckItem.computeFrequency(reader, fieldName);
        String higher = spellcheckItem.getHigher();
        if (higher != null)
            highers.add(higher);
    }
    suggestion = StringUtils.join(highers, ' ');
}

From source file:com.leavesfly.lia.tool.SpellCheckerExample.java

License:Apache License

public static void main(String[] args) throws IOException {

    if (args.length != 2) {
        System.out.println("Usage: java lia.tools.SpellCheckerTest SpellCheckerIndexDir wordToRespell");
        System.exit(1);//  www  .j a va2  s  . c o  m
    }

    String spellCheckDir = args[0];
    String wordToRespell = args[1];

    Directory dir = FSDirectory.open(new File(spellCheckDir));
    if (!IndexReader.indexExists(dir)) {
        System.out.println("\nERROR: No spellchecker index at path \"" + spellCheckDir
                + "\"; please run CreateSpellCheckerIndex first\n");
        System.exit(1);
    }
    SpellChecker spell = new SpellChecker(dir); //#A

    spell.setStringDistance(new LevensteinDistance()); //#B
    //spell.setStringDistance(new JaroWinklerDistance());

    String[] suggestions = spell.suggestSimilar(wordToRespell, 5); //#C
    System.out.println(suggestions.length + " suggestions for '" + wordToRespell + "':");
    for (String suggestion : suggestions)
        System.out.println("  " + suggestion);
}

From source file:engine.easy.util.SuggestionSpellService.java

License:Apache License

public static void main(String[] args) throws Exception {

    File dir = new File(AppConstants.DICTIONARY_INDEX_PATH);

    Directory directory = FSDirectory.open(dir);

    SpellChecker spellChecker = new SpellChecker(new RAMDirectory());

    spellChecker.indexDictionary(new PlainTextDictionary(new File(AppConstants.DICTIONARY_PATH)));

    String wordForSuggestions = "hee";

    int suggestionsNumber = 3;

    String[] suggestions = spellChecker.suggestSimilar(wordForSuggestions, suggestionsNumber);

    if (suggestions != null && suggestions.length > 0) {
        for (String word : suggestions) {
            System.out.println("Did you mean:" + word);
        }/*from  ww  w  .  ja v  a2  s .com*/
    } else {
        System.out.println("No suggestions found for word:" + wordForSuggestions);
    }
}

From source file:es.pode.indexador.negocio.servicios.busqueda.SrvBuscadorServiceImpl.java

License:Open Source License

/**
 * @see es.pode.indexador.negocio.servicios.busqueda.SrvBuscadorService#busquedaSimple(es.pode.indexador.negocio.servicios.busqueda.ParamSimpleVO)
 * @param ParamSimpleVO Este VO alberga los parametros aceptados en la busqueda simple.
 * @return DocumentosVO Esta clase representa los resultados de una busqueda. 
 */// w  w  w. j a v a  2 s  .co m
protected es.pode.indexador.negocio.servicios.busqueda.DocumentosVO handleBusquedaSimple(
        es.pode.indexador.negocio.servicios.busqueda.ParamSimpleVO paramBusq) throws java.lang.Exception {

    DocumentosVO respuesta = new DocumentosVO();

    if (logger.isDebugEnabled())
        logger.debug("Los par metros son idiomaBusqueda[" + paramBusq.getIdiomaBusqueda()
                + "] idiomaNavegacion [" + paramBusq.getIdiomaNavegacion() + "] palabarasclave ["
                + paramBusq.getPalabrasClave() + "]");

    DisjunctionMaxQuery query = new DisjunctionMaxQuery(0.01f);
    Hits hits = this.internaBusquedaSimple(paramBusq, query);
    if (logger.isDebugEnabled())
        logger.debug("Se devuelven los hits");

    if (hits != null && hits.length() == 0) {
        if (logger.isDebugEnabled())
            logger.debug("Se devuelven los hits NULL o 0 vamos a por las sugerencias");
        Directory directorioIndiceSpell = this.indiceSpell(paramBusq.getIdiomaBusqueda());

        if (logger.isDebugEnabled())
            logger.debug("El indice de spellchecker es " + directorioIndiceSpell);
        SpellChecker spellChecker = new SpellChecker(directorioIndiceSpell);
        String sQuery = query.toString();

        if (!spellChecker.exist(sQuery)
                && (paramBusq.getPalabrasClave() != null && !paramBusq.getPalabrasClave().equals(""))) {
            String[] sugerencias = spellChecker.suggestSimilar(paramBusq.getPalabrasClave().toLowerCase(), 10);
            respuesta.setSugerencias(sugerencias);
        } else
            respuesta.setSugerencias(new String[] {});
    } else {
        respuesta.setResultados(this.getArrayDocsFromHits(hits,
                (hits.length() > paramBusq.getNumeroResultados().intValue())
                        ? paramBusq.getNumeroResultados().intValue()
                        : hits.length()));
    }
    return respuesta;
}

From source file:es.pode.indexador.negocio.servicios.busqueda.SrvBuscadorServiceImpl.java

License:Open Source License

/**
 * @see es.pode.indexador.negocio.servicios.busqueda.SrvBuscadorService#busquedaAvanzada(es.pode.indexador.negocio.servicios.busqueda.ParamAvanzadoVO)
 * @param ParamAvanzadoVO VO que alberga los parametros que acepta una busqueda avanzada.
 * @return DocumentosVO Esta clase representa los resultados de una busqueda. 
 *//*from w  w w.  j a  va2  s.c  o  m*/
protected es.pode.indexador.negocio.servicios.busqueda.DocumentosVO handleBusquedaAvanzada(
        es.pode.indexador.negocio.servicios.busqueda.ParamAvanzadoVO paramBusq) throws java.lang.Exception {

    //      Implementamos la busqueda avanzada.
    DocumentosVO respuesta = new DocumentosVO();
    if (logger.isDebugEnabled())
        logger.debug("SrvBuscadorServiceImpl - handleBusquedaAvanzada: Parametros de la busqueda avanzada "
                + paramBusqAvanz2String(paramBusq));
    DisjunctionMaxQuery query = new DisjunctionMaxQuery(0.01f);
    long start = System.currentTimeMillis();
    Object[] hits = null;
    boolean resultadoUnico = false;

    // Some fixing with "*" and ".*"
    if (paramBusq.getPalabrasClave() != null && !paramBusq.getPalabrasClave().trim().equals("*")
            && !paramBusq.getPalabrasClave().trim().equals(".*")) {
        if (paramBusq.getPalabrasClave().trim().toLowerCase()
                .startsWith(props.getProperty("agrega_admin") + " ")) {
            hits = new Hits[1];
            hits = this.internaBusquedaQuery(paramBusq, paramBusq.getPalabrasClave().toLowerCase().trim()
                    .substring((props.getProperty("agrega_admin") + " ").length()), query, false, null);
        } else if (paramBusq.getPalabrasClave().trim().toLowerCase()
                .startsWith(props.getProperty("agrega_todos") + " ")) {
            IndiceVO[] idiomas = this.handleObtenerIdiomasBusqueda();
            hits = new Hits[idiomas.length];
            hits = this.internaBusquedaQuery(paramBusq, paramBusq.getPalabrasClave().toLowerCase().trim()
                    .substring((props.getProperty("agrega_todos") + " ").length()), query, true, idiomas);
        } else {
            resultadoUnico = true;
            hits = new Hits[1];
            hits[0] = internaBusquedaAvanzada(paramBusq, query);
        }
    } else {
        resultadoUnico = true;
        hits = new Hits[1];
        hits[0] = internaBusquedaAvanzada(paramBusq, query);
    }
    long end = System.currentTimeMillis();
    logger.debug("SrvBuscadorServiceImpl - handleBusquedaAvanzada : Busqueda local realizada en ="
            + (end - start) + " milisegundos.");
    if (logger.isDebugEnabled()) {
        logger.debug("Se devuelven los hits");
        logger.debug("Se devuelven los hits NULL o 0 vamos a por las sugerencias");
    }
    if (paramBusq.getBusquedaSimpleAvanzada() != null
            && !paramBusq.getBusquedaSimpleAvanzada().equals(BUSCARRSS)) {
        try {
            Directory directorioIndiceSpell = this.indiceSpell(paramBusq.getIdiomaBusqueda());
            if (logger.isDebugEnabled())
                logger.debug("El indice de spellchecker es " + directorioIndiceSpell);
            SpellChecker spellChecker = new SpellChecker(directorioIndiceSpell);
            String sQuery = query.toString();
            //         TODO: retocar las sugerencias para que tengan en cuenta algo mas que los parametros de "keywords"?
            if (!spellChecker.exist(sQuery)
                    && (paramBusq.getPalabrasClave() != null && !paramBusq.getPalabrasClave().equals(""))) {
                List claveBusqueda = this.obtenerPalabrasClave(paramBusq.getPalabrasClave().toLowerCase(),
                        false);
                List<String> sugerencias = new ArrayList<String>();
                if (claveBusqueda != null && claveBusqueda.size() > 0) {
                    boolean suficientes = false;
                    for (int i = 0; i < claveBusqueda.size() && !suficientes; i++) {
                        if (!((String) claveBusqueda.get(i)).equals("")) {
                            String[] suge = spellChecker.suggestSimilar((String) claveBusqueda.get(i),
                                    NUMERO_SUGERENCIAS);
                            if (suge != null && suge.length > 0) {
                                for (int k = 0; k < suge.length
                                        && sugerencias.size() < NUMERO_SUGERENCIAS; k++) {
                                    boolean encontrado = false;
                                    for (int j = 0; j < sugerencias.size() && !encontrado; j++) {
                                        if (sugerencias.get(j).toString().equals(suge[k]))
                                            encontrado = true;
                                    }
                                    if (!encontrado && validarPersonalizada(paramBusq)) {
                                        Hits hitSugerencias = null;
                                        ParamAvanzadoVO paramBusqSug = paramBusq;
                                        paramBusqSug.setPalabrasClave(suge[k]);
                                        try {
                                            hitSugerencias = internaBusquedaAvanzada(paramBusqSug, query);
                                            if (hitSugerencias != null && hitSugerencias.length() > 0)
                                                sugerencias.add(suge[k]);
                                        } catch (Exception e) {
                                            logger.error(
                                                    "SrvBuscadorServiceImpl - handleBuscarAvanzado:Error solicitando comprobaci n sugerencia avanzada. Sugerencia="
                                                            + suge[k],
                                                    e);
                                        }
                                    } else if (!encontrado && !validarPersonalizada(paramBusq))
                                        sugerencias.add(suge[k]);
                                }
                            }
                            if (sugerencias.size() == NUMERO_SUGERENCIAS)
                                suficientes = true;
                        }
                    }
                }
                String[] cargarSugerencias = new String[] {};
                if (sugerencias != null && sugerencias.size() > 0) {
                    cargarSugerencias = new String[sugerencias.size()];
                    for (int i = 0; i < sugerencias.size(); i++) {
                        cargarSugerencias[i] = sugerencias.get(i);
                    }
                }
                respuesta.setSugerencias(cargarSugerencias);
            } else
                respuesta.setSugerencias(new String[] {});
        } catch (Exception e) {
            logger.error(
                    "SrvBuscadorServiceImpl - handleBuscarAvanzado:Error solicitando sugerencias para idioma:"
                            + paramBusq.getIdiomaBusqueda(),
                    e);
            respuesta.setSugerencias(new String[] {});
        }
        try {
            es.pode.indexador.negocio.servicios.busqueda.TaxonVO[] cargarTesauros = new es.pode.indexador.negocio.servicios.busqueda.TaxonVO[] {};
            if (paramBusq.getPalabrasClave() != null && !paramBusq.getPalabrasClave().trim().equals("")) {
                List palabrasTesauro = this.obtenerPalabrasClave(paramBusq.getPalabrasClave().toLowerCase(),
                        true);
                List<String> nombreTesauros = new ArrayList<String>();
                List<String> identificadorTesauros = new ArrayList<String>();
                if (palabrasTesauro != null && palabrasTesauro.size() > 0) {
                    int numeroTax = 0;
                    for (int i = 0; i < palabrasTesauro.size()
                            && (numeroTax < Integer.parseInt(props.getProperty("numero_tesauros"))); i++) {
                        TaxonVO[] taxones = this.getSrvTesaurosServices().obtenerTerminosRelacionadosPorTexto(
                                (String) palabrasTesauro.get(i), props.getProperty("nombre_tesauro"),
                                paramBusq.getIdiomaBusqueda());
                        String[] idTesauro = new String[taxones.length];
                        for (int k = 0; k < taxones.length; k++) {
                            idTesauro[k] = taxones[k].getId();
                        }
                        for (int k = 0; k < taxones.length
                                && (numeroTax < Integer.parseInt(props.getProperty("numero_tesauros"))); k++) {
                            Integer[] tesauros = NumTermsArbol
                                    .obtenerNumeroNodos(idTesauro,
                                            getIndexPathByLanguage(paramBusq.getIdiomaBusqueda()), "tesauro")
                                    .getConteo();
                            if (idTesauro != null && idTesauro.length != 0) {
                                for (int j = 0; j < idTesauro.length; j++) {
                                    if (idTesauro[j].equals(taxones[k].getId())) {
                                        if (tesauros[j].intValue() > 0) {
                                            nombreTesauros.add(taxones[k].getValorTax());
                                            identificadorTesauros.add(taxones[k].getId());
                                            numeroTax = numeroTax + 1;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                if (nombreTesauros != null && nombreTesauros.size() > 0) {
                    cargarTesauros = new es.pode.indexador.negocio.servicios.busqueda.TaxonVO[nombreTesauros
                            .size()];
                    for (int i = 0; i < nombreTesauros.size(); i++) {
                        cargarTesauros[i] = new es.pode.indexador.negocio.servicios.busqueda.TaxonVO(
                                identificadorTesauros.get(i).toString(), nombreTesauros.get(i).toString());
                    }
                }
                respuesta.setTesauros(cargarTesauros);
            } else
                respuesta.setTesauros(new es.pode.indexador.negocio.servicios.busqueda.TaxonVO[] {});
        } catch (Exception e) {
            logger.error(
                    "SrvBuscadorServiceImpl - handleBuscarAvanzado:Error obteniendo sugerencias de tesauro ["
                            + props.getProperty("nombre_tesauro") + "] con:" + paramBusq.getPalabrasClave()
                            + " n mero de tesauros m ximo solicitado=" + props.getProperty("numero_tesauros")
                            + " e idioma=" + paramBusq.getIdiomaBusqueda(),
                    e);
            respuesta.setTesauros(new es.pode.indexador.negocio.servicios.busqueda.TaxonVO[] {});
        }
    }
    if (hits == null || (resultadoUnico && hits[0] == null)) {
        respuesta.setTotalResultados(new Integer(0));
        respuesta.setNumeroResultados(new Integer(0));
        respuesta.setNumDocumentosIndice(new Integer(0));
    } else {
        long start2 = System.currentTimeMillis();
        if (hits.length > 1) {
            int totalResultados = 0;
            List docsList = new ArrayList();
            for (int i = 0; i < hits.length
                    && docsList.size() <= paramBusq.getNumeroResultados().intValue(); i++) {
                if (hits[i] != null && ((Hits) hits[i]).length() > 0) {
                    totalResultados = totalResultados + ((Hits) hits[i]).length();
                    DocVO[] docs = this.getArrayDocsFromHits((Hits) hits[i],
                            ((((Hits) hits[i]).length() < paramBusq.getNumeroResultados().intValue())
                                    || paramBusq.getNumeroResultados().intValue() == -1)
                                            ? ((Hits) hits[i]).length()
                                            : paramBusq.getNumeroResultados().intValue());
                    for (int j = 0; j < docs.length; j++) {
                        docsList.add(docs[j]);
                    }
                }
            }
            DocVO[] docs = new DocVO[docsList.size()];
            for (int i = 0; i < docs.length; i++) {
                docs[i] = (DocVO) docsList.get(i);
            }
            respuesta.setTotalResultados(new Integer(totalResultados));
            respuesta.setResultados(docs);
        } else {
            respuesta.setTotalResultados(new Integer(((Hits) hits[0]).length()));
            respuesta.setResultados(this.getArrayDocsFromHits((Hits) hits[0],
                    ((((Hits) hits[0]).length() < paramBusq.getNumeroResultados().intValue())
                            || paramBusq.getNumeroResultados().intValue() == -1) ? ((Hits) hits[0]).length()
                                    : paramBusq.getNumeroResultados().intValue()));
        }
        end = System.currentTimeMillis();
        logger.debug("SrvBuscadorServiceImpl - handleBusquedaAvanzada : Mapeo local realizado en ="
                + (end - start2) + " milisegundos.");
        IndexReader reader = IndexReader.open(this.getIndexByLanguage(paramBusq.getIdiomaBusqueda()));
        respuesta.setNumDocumentosIndice(new Integer(reader.numDocs()));
        respuesta.setNumeroResultados(new Integer(respuesta.getResultados().length));
    }
    logger.debug("SrvBuscadorServiceImpl - handleBusquedaAvanzada : Busqueda local realizada en ="
            + (end - start) + " milisegundos.");
    return respuesta;
}

From source file:fastcampus.lucene.example.search.SpellCheckerExample.java

License:Apache License

public static void main(String[] args) throws Exception {
    Directory directory = FSDirectory.open(Paths.get("./index/spell/"));
    SpellChecker spellChecker = new SpellChecker(directory);

    //Analyzer analyzer = new StandardAnalyzer();                             // ? 
    Analyzer analyzer = new Analyzer() {
        @Override//from  w w  w . j a  v a2 s .  co  m
        protected TokenStreamComponents createComponents(String s) {
            Reader reader = new StringReader(s);
            Tokenizer tokenizer = new StandardTokenizer();
            tokenizer.setReader(reader);
            String name = "nfc_cf";
            Normalizer2 normalizer = Normalizer2.getInstance(null, name, Normalizer2.Mode.DECOMPOSE);
            TokenFilter filter = new ICUNormalizer2Filter(tokenizer, normalizer);
            return new TokenStreamComponents(tokenizer, filter);
        }
    };

    IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer); //?? Writer? ?  ?

    Path path = Paths.get("./data/spell/dic.txt");

    spellChecker.setSpellIndex(directory);
    spellChecker.clearIndex();
    spellChecker.indexDictionary(new PlainTextDictionary(path), indexWriterConfig, true);
    String wordForSuggestions = "?";
    //spellChecker.setStringDistance(new LevensteinDistance());  //#Levenstein  
    spellChecker.setStringDistance(new JaroWinklerDistance()); //Jaro-Winkler 

    int suggestionsNumber = 1;
    String[] suggestions = spellChecker.suggestSimilar(wordForSuggestions, suggestionsNumber);
    if (suggestions != null && suggestions.length > 0) {

        for (String word : suggestions) {

            System.out.println("Did you mean:" + word);

        }

    } else {

        System.out.println("No suggestions found for word:" + wordForSuggestions);

    }

}

From source file:fr.mael.microrss.dao.impl.GenericDaoImpl.java

License:Open Source License

/**
 * @see fr.mael.jmusic.dao.GenericDao#getSuggestions(java.lang.String)
 *//*from w  w  w. j av a 2 s  .  co  m*/
@Override
public String[] getSuggestions(String query) throws IOException {
    Directory directory = FSDirectory
            .open(new File(configuration.getIndexDir() + "/spell_" + getPersistentClass().getName()));
    SpellChecker spell = new SpellChecker(directory);
    spell.setStringDistance(new LevensteinDistance());
    spell.setAccuracy(configuration.getSuggestionAccuracy());
    return spell.suggestSimilar(query, configuration.getSuggestionNumber());
}

From source file:lucee.runtime.search.lucene2.LuceneSearchCollection.java

License:Open Source License

@Override
public SearchResulItem[] _search(SearchData data, String criteria, String language, short type,
        String categoryTree, String[] category) throws SearchException {
    try {/*from  w w  w .  j ava2  s . co m*/

        if (type != SEARCH_TYPE_SIMPLE)
            throw new SearchException("search type explicit not supported");
        Analyzer analyzer = SearchUtil.getAnalyzer(language);
        Query query = null;
        Op op = null;
        Object highlighter = null;
        lucee.runtime.search.lucene2.query.QueryParser queryParser = new lucee.runtime.search.lucene2.query.QueryParser();
        AddionalAttrs aa = AddionalAttrs.getAddionlAttrs();
        aa.setHasRowHandling(true);
        int startrow = aa.getStartrow();
        int maxrows = aa.getMaxrows();

        if (!criteria.equals("*")) {
            // FUTURE take this data from calling parameters
            op = queryParser.parseOp(criteria);
            if (op == null)
                criteria = "*";
            else
                criteria = op.toString();
            try {

                query = new QueryParser("contents", analyzer).parse(criteria);
                highlighter = Highlight.createHighlighter(query, aa.getContextHighlightBegin(),
                        aa.getContextHighlightEnd());

            } catch (ParseException e) {
                throw new SearchException(e);
            }
        }

        Resource[] files = _getIndexDirectories();

        if (files == null)
            return new SearchResulItem[0];
        ArrayList<SearchResulItem> list = new ArrayList<SearchResulItem>();
        String ct, c;

        ArrayList<String> spellCheckIndex = spellcheck ? new ArrayList<String>() : null;

        int count = 0;
        IndexReader reader = null;
        Searcher searcher = null;
        try {
            outer: for (int i = 0; i < files.length; i++) {
                if (removeCorrupt(files[i]))
                    continue;
                String strFile = files[i].toString();
                SearchIndex si = indexes.get(files[i].getName());

                if (si == null)
                    continue;
                ct = si.getCategoryTree();
                c = ListUtil.arrayToList(si.getCategories(), ",");

                // check category tree
                if (!matchCategoryTree(ct, categoryTree))
                    continue;
                if (!matchCategories(si.getCategories(), category))
                    continue;

                Document doc;
                String id = files[i].getName();
                data.addRecordsSearched(_countDocs(strFile));

                reader = _getReader(id, false);
                if (query == null && "*".equals(criteria)) {
                    int len = reader.numDocs();
                    for (int y = 0; y < len; y++) {
                        if (startrow > ++count)
                            continue;
                        if (maxrows > -1 && list.size() >= maxrows)
                            break outer;
                        doc = reader.document(y);
                        list.add(createSearchResulItem(highlighter, analyzer, doc, id, 1, ct, c,
                                aa.getContextPassages(), aa.getContextBytes()));
                    }
                } else {
                    if (spellcheck)
                        spellCheckIndex.add(id);
                    // search
                    searcher = new IndexSearcher(reader);
                    Hits hits = searcher.search(query);
                    int len = hits.length();
                    for (int y = 0; y < len; y++) {
                        if (startrow > ++count)
                            continue;
                        if (maxrows > -1 && list.size() >= maxrows)
                            break outer;
                        //list.add(new SearchResulItemHits(hits,y,highlighter,analyzer,id,ct,c,aa.getContextPassages(),aa.getContextBytes()));
                        doc = hits.doc(y);
                        list.add(createSearchResulItem(highlighter, analyzer, doc, id, hits.score(y), ct, c,
                                aa.getContextPassages(), aa.getContextBytes()));
                    }

                }

            }
        } finally {
            close(reader);
            close(searcher);
        }

        // spellcheck
        //SearchData data=ThreadLocalSearchData.get();
        if (spellcheck && data != null) {
            if (data.getSuggestionMax() >= list.size()) {

                Map suggestions = data.getSuggestion();
                Iterator it = spellCheckIndex.iterator();
                String id;
                Literal[] literals = queryParser.getLiteralSearchedTerms();
                String[] strLiterals = queryParser.getStringSearchedTerms();
                boolean setSuggestionQuery = false;
                while (it.hasNext()) {
                    id = (String) it.next();
                    // add to set to remove duplicate values
                    SuggestionItem si;
                    SpellChecker sc = getSpellChecker(id);
                    for (int i = 0; i < strLiterals.length; i++) {
                        String[] arr = sc.suggestSimilar(strLiterals[i], 1000);
                        if (arr.length > 0) {
                            literals[i].set("<suggestion>" + arr[0] + "</suggestion>");
                            setSuggestionQuery = true;

                            si = (SuggestionItem) suggestions.get(strLiterals[i]);
                            if (si == null)
                                suggestions.put(strLiterals[i], new SuggestionItem(arr));
                            else
                                si.add(arr);
                        }
                    }
                }
                if (setSuggestionQuery)
                    data.setSuggestionQuery(op.toString());
            }
        }

        return list.toArray(new SearchResulItem[list.size()]);
    } catch (IOException e) {
        throw new SearchException(e);
    }

}