上周在使用範圍搜尋時又遇到問題 ,程式抛出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", true, true);
} else if (advancedSearchVO.getViewedRank() == 2) ...{
return new RangeFilter("viewedcount", "0000000100",
"0000001000", true, true);
} else if (advancedSearchVO.getViewedRank() == 3) ...{
return new RangeFilter("viewedcount", "0000001000",
"0000010000", true, true);
} else if (advancedSearchVO.getViewedRank() == 4) ...{
return new RangeFilter("viewedcount", "0000010000",
"0150000000", true, true);
}
}
再使用
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", true, true));
} else if (advancedSearchVO.getViewedRank() == 2) ...{
filterList.add(new RangeFilter("viewedcount", "0000000100",
"0000001000", true, true));
} else if (advancedSearchVO.getViewedRank() == 3) ...{
filterList.add(new RangeFilter("viewedcount", "0000001000",
"0000010000", true, true));
} else if (advancedSearchVO.getViewedRank() == 4) ...{
filterList.add(new RangeFilter("viewedcount", "0000010000",
"0150000000", true, true));
}
}
...........................
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);
。。。。