解决lucene范围搜索中的TooManyClauses exception

上周在使用范围搜索时又遇到问题 ,程序抛出TooManyClauses  exception。后来才发现lucene将范围搜索转化为精确匹配,每个匹配对应一个clause,所以如果你的范围如果包含超过1024个索引值,程序就会抛错

由此想到3种方案

1)

既然lucene限制了clause的个数,那么可以通过

BooleanQuery.setMaxClauseCount(Integer.MAX_VALUE)

改变限制,这个可以解决问题,但有隐患,如果某个范围的索引特别多,内存会有爆掉的危险。

2)根据应用修改索引

比如你有一个范围是视频观看数量(viewedcount) 1000-10000,那么你可以将这个范围内的所有的视频定为一个值(viewedcountlevel),也就是应用的每个搜索范围定为一个值,一个应用了不起10个范围,那么对范围档次建索引,到时候搜的根据 viewedcountlevel而不是viewedcount,将范围搜索以应用的角度转化为精确搜

 

3)使用filter

比如产生一个RangeFilter

if  (advancedSearchVO.getViewedRank()  >   0 {
   
if (advancedSearchVO.getViewedRank() == 1{
       
return new RangeFilter("viewedcount""0000000000",
      
"0000000100"truetrue);
   }
 else if (advancedSearchVO.getViewedRank() == 2{
       
return new RangeFilter("viewedcount""0000000100",
      
"0000001000"truetrue);
   }
 else if (advancedSearchVO.getViewedRank() == 3{
       
return new RangeFilter("viewedcount""0000001000",
      
"0000010000"truetrue);
   }
 else if (advancedSearchVO.getViewedRank() == 4{
      
return  new RangeFilter("viewedcount""0000010000",
      
"0150000000"truetrue);
   }

  }


再使用

IndexSearch.search(Query query,Filter filter),

 

个人比较喜欢最后一种方案,第一种有潜在的危险,第二种又有些脆弱(索引受应用影响大,不稳定),最后一种比较折中一点

前面所说的咚咚确实解决了一个filter的问题,如果你有多个范围搜索,也就是说通常你需要多个filter, filter如何嵌套?

首先建立一个filterlist

public  List buildFilterList(ISearchVO searchVO)  {
        List filterList 
= new ArrayList();
        
        ..........................                                  
    
if (advancedSearchVO.getViewedRank() > 0{
            
if (advancedSearchVO.getViewedRank() == 1{
                  
 filterList.add(new RangeFilter("viewedcount""0000000000",
                        
"0000000100"truetrue));
            }
 else if (advancedSearchVO.getViewedRank() == 2{
               
    filterList.add(new RangeFilter("viewedcount""0000000100",
                        
"0000001000"truetrue));
            }
 else if (advancedSearchVO.getViewedRank() == 3{
               
    filterList.add(new RangeFilter("viewedcount""0000001000",
                        
"0000010000"truetrue));
            }
 else if (advancedSearchVO.getViewedRank() == 4{
              
     filterList.add(new RangeFilter("viewedcount""0000010000",
                        
"0150000000"truetrue));
            }

        }


        ...........................
        
return filterList;
    }

然后嵌套

public  Query buildFilteredQuery(List filterlist, Query query)  {

        
if (filterlist == null || filterlist.size() < 1{
            
return query;
        }


        FilteredQuery filteredQuery 
= null;
        
for (int i = 0; i < filterlist.size(); i++{
            
if (i == 0{
                filteredQuery 
= new FilteredQuery(query, (Filter) filterlist
                        .get(i));
            }
 else {

                filteredQuery 
= new FilteredQuery(filteredQuery,
                        (Filter) filterlist.get(i));
            }

        }


        
return filteredQuery;

    }

最后

query  =  buildQuery();
。。。。
query 
=  buildFilteredQuery( this .buildFilterList(searchVO), query);
Hits hits 
=  searcher.search(query, sort);
。。。。

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值