您的位置:首页 > 产品设计 > UI/UE

Lucene.Net学习 TermQuery,NumericRangeQuery,TermRangeQuery的使用(一)

2012-10-23 00:57 633 查看
/// <summary>
/// 搜索
/// </summary>
/// <param name="k"></param>
/// <param name="cid"></param>
/// <returns></returns>
public ActionResult Search(string k, string p, DateTime? startDate, DateTime? endDate)
{
Stopwatch st = new Stopwatch();
st.Start();//计时开始
//为索引存储目录
string INDEX_STORE_PATH = Server.MapPath("~/SearchIndex");
var ver = Lucene.Net.Util.Version.LUCENE_29;
Directory indexDirectory = FSDirectory.Open(new System.IO.DirectoryInfo(INDEX_STORE_PATH));
Analyzer analyzer = new StandardAnalyzer(ver);
IndexSearcher searcher = null;
List<Article> list;
int recCount = 0;
bool isk = !string.IsNullOrEmpty(k),
isp = !string.IsNullOrEmpty(p),
isstartdate = startDate.HasValue,
isenddate = endDate.HasValue;

try {
searcher = new IndexSearcher(indexDirectory, true);

BooleanQuery booleanQuery = new BooleanQuery();
/*
* 多字段查询同时搜索title和summary
*/
//string[] fields = { "title", "summary" };
//MultiFieldQueryParser parser = new MultiFieldQueryParser(ver, fields, analyzer);
//Query query = parser.Parse(k);
//Query query1 = new QueryParser(ver, "classid", analyzer).Parse("1");

/*
* TermQuery搜索文档的最小单位
* 如果不分词索引,只能整体都符合才能命中
* 如classname以不分词的形式索引
* classname="体育新闻"
* 你只搜体育或新闻是不能命中的,只有收体育新闻才能命中
* TermQuery适合用来搜索Id,classname之类的索引
*/
//Query query1 = new TermQuery(new Term("id", "1"));
//Query query2 = new TermQuery(new Term("classname", k));

/*
* QueryParser支持分词索引支持类似sql语句的查询等,
* 搜索形式是把你输入的关键字先分词,分词之后再拿来搜索
* 当然由于自带的StandardAnalyzer对中文分词不怎么好,
* (经测试StandardAnalyzer对中文的分词不会一空格来分词)
* 我们就拿英文搜索来说吧。
* 例如我们输入的关键字为 I love you
* 他会先把I love you 分词 可能 分成 I/love/you/i love/ i love you/具体怎么分大家可以试试看
* 然后再拿来搜索,如果你的文档中存在 i 或者 love 或者you都会命中
* 注意:使用QueryParser的搜索当k为Empty或null时会报错注意处理
*/
//查询关键字
if (isk) {
Query query3 = new QueryParser(ver, "title", analyzer).Parse(k);
booleanQuery.Add(query3, BooleanClause.Occur.MUST);
}
/*
* NumericRangeQuery按范围搜索,前提是搜索的字段必须是以NumericField文档索引
* NumericRangeQuery可以对数字、日期、时间进行范围搜索
* 对日期和时间搜索时,先把日期转成数字存索引,查询时也是把日期转成数字再查询,
* 但是此种方法日期转换比较麻烦
*/
//按价格范围搜索(对数字搜索)
if (isp) {
string[] prices = p.Split(new char[] { '_' });
float min = float.Parse(prices[0]);
float max = prices.Length < 2 ? 10000000000.00f : float.Parse(prices[1]);
Query query4 = NumericRangeQuery.NewFloatRange("price", min, max, true, true);
booleanQuery.Add(query4, BooleanClause.Occur.MUST);
}

/*
* TermRangeQuery具体什么原理还不那么明白,有待研究
*/
//按日期范围搜索(对日期搜索)
if (isstartdate || isenddate) {
string mindate = isstartdate ? startDate.Value.ToString("yyyy-MM-dd")
: DateTime.MinValue.ToString("yyyy-MM-dd");
string maxdate = isenddate ? endDate.Value.ToString("yyyy-MM-dd")
: DateTime.Today.ToString("yyyy-MM-dd");
Query query5 = new TermRangeQuery("createtime", mindate, maxdate, true, true);
booleanQuery.Add(query5, BooleanClause.Occur.MUST);
}

//如果没有查询关键字则显示全部的数据
if (!isk && !isp && !isstartdate && !isenddate) {
Query query6 = new TermQuery(new Term("all", "all"));
booleanQuery.Add(query6, BooleanClause.Occur.MUST);
}

//执行搜索,获取查询结果集对象
TopDocs ts = searcher.Search(booleanQuery, null, 100);
//ts = searcher.MaxDoc();

recCount = ts.totalHits;//获取命中的文档个数
ScoreDoc[] hits = ts.scoreDocs;//获取命中的文档信息对象
st.Stop();//计时停止
ViewBag.EvenTime = string.Format("{0}毫秒,生成的Query语句:{1}",
st.ElapsedMilliseconds, booleanQuery.ToString());
ViewBag.Count = recCount;
list = new List<Article>();
foreach (var item in hits) {
list.Add(new Article()
{
Id = searcher.Doc(item.doc).Get("id"),
ClassId = searcher.Doc(item.doc).Get("classid"),
ClassName = searcher.Doc(item.doc).Get("classname"),
Title = searcher.Doc(item.doc).Get("title"),
Price = float.Parse(searcher.Doc(item.doc).Get("price")),
//Summary = searcher.Doc(item.doc).Get("summary"),
Score = item.score.ToString(),
CreateTime = Convert.ToDateTime(searcher.Doc(item.doc).Get("createtime"))
});
}
} catch (Exception) {
throw;
} finally {
if (searcher != null) {
searcher.Close();
}
}

return View(list);
}


最后效果:

1.什么条件也不给,显示全部



2.按日期查询



如有不明白或想拍砖请留言或加QQ群63181865一起学习图片有点大请另存为后再看
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: