zoukankan      html  css  js  c++  java
  • Lucene.Net 的“System.IndexOutOfRangeException: 索引超出了数组界限”错误

    堆栈信息如下

    System.IndexOutOfRangeException: 索引超出了数组界限。

       在 Lucene.Net.Search.AnonymousClassIntParser1.ParseInt(String val)

       在 Lucene.Net.Search.FieldCacheImpl.IntCache.CreateValue(IndexReader reader, Entry entryKey)

       在 Lucene.Net.Search.FieldCacheImpl.Cache.Get(IndexReader reader, Entry key)

       在 Lucene.Net.Search.FieldCacheImpl.GetInts(IndexReader reader, String field, IntParser parser)

       在 Lucene.Net.Search.FieldCacheImpl.IntCache.CreateValue(IndexReader reader, Entry entryKey)

       在 Lucene.Net.Search.FieldCacheImpl.Cache.Get(IndexReader reader, Entry key)

       在 Lucene.Net.Search.FieldCacheImpl.GetInts(IndexReader reader, String field, IntParser parser)

       在 Lucene.Net.Search.FieldCacheImpl.GetInts(IndexReader reader, String field)

    判断

    这个错误很常见,一般都是数组引起的,所以可以很容易定位到lucene代码,在FieldCache.cs中的val[0],说明输入可能为null或者string.empty:

            public virtual int ParseInt(System.String val)
            {
                int shift = val[0] - NumericUtils.SHIFT_START_INT;
                if (shift > 0 && shift <= 31)
                    throw new FieldCacheImpl.StopFillCacheException();
                return NumericUtils.PrefixCodedToInt(val);
            }

    尝试一

    AnonymousClassIntParser1是默认给数值字段解码的,当通过FieldCache获取字段值时就会用它来解码还原为数值。lucene不是数据库,没有数据完整性的保证,这个是倒排索引的代价,既然只是绕过空的数值字段,那么用类似int.TryParse()的方式从最下面试试看。修改后错误确实消失了,同时排序也消失了。

    尝试二

    刚刚说了lucene的设计是没有数据完整性保证的,上面代码中“StopFillCacheException”就是证据,上面的尝试不行后我就开始分析这次调用的过程,也就是FieldCacheImpl.cs。IDictionary<Type, Cache> caches,就是关键的缓存变量,其实一看就知道这个类的作用了。那么再往里看Cache的实现,这里以IntCache为例,这是个内部类,尽在这个字段缓存类中使用。它的作用就是缓存对同一字段的读取,比如文档001的Title,第一次读取后就会被缓存下来,后面的访问都是使用内存中的缓存。

                    try
                    {
                        do
                        {
                            Term term = termEnum.Term;
                            if (term == null || (System.Object) term.Field != (System.Object) field)
                                break;
                            int termval = parser.ParseInt(term.Text);
                            if (retArray == null)
                                // late init
                                retArray = new int[reader.MaxDoc];
                            termDocs.Seek(termEnum);
                            while (termDocs.Next())
                            {
                                retArray[termDocs.Doc] = termval;
                            }
                        } while (termEnum.Next());
                    }
                    catch (StopFillCacheException)
                    {
                    }
                    catch (IndexOutOfRangeException exc)
                    {
                    }
                    finally
                    {
                        termDocs.Close();
                        termEnum.Close();
                    }

    上面是我修改后的版本,增加了IndexOutOfRangeException的异常捕捉。搜索结果好了,但是为题还没有根本解决,这里会在第一个出现异常的文档后就终止读取缓存,不过好过不能使用数值字段。完美的解决办法后面会继续跟进。

    作者:KKcat
        
    个人博客:http://jinzhao.me/
        
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    第五周:项目日记(3)
    第四周:项目日记(2)
    第三周:项目日记(1)
    需求获取常见的方法是进行客户访谈,结合你的实践谈谈会遇到什么问题,你是怎么解决的?
    面向过程(或者叫结构化)分析方法与面向对象分析方法到底区别在哪里?请根据自己的理解简明扼要的回答。
    你认为一些军事方面的软件系统采用什么样的开发模型比较合适?
    第八周作业
    第七周作业
    当下大部分互联网创业公司为什么都愿意采用增量模型来做开发?
    第五周作业
  • 原文地址:https://www.cnblogs.com/jinzhao/p/2966244.html
Copyright © 2011-2022 走看看