几个注意事项
1.建立索引时 插入的顺序(不设置document和字段的boost) 会影响到 查询结果的默认排序,建议:将最新生成的文章 最后建索引 这样 查询结果首先显示的是 最后插入的数据
2.BooleanQuery的多条件查询 一定是多个 must的组合,否则就不是 and关系了,如下代码:
3.查询时候亦可对 结果进行权重排序,通过设置Query的Boost属性即可,如下述代码所示
4.查询时,通常首先对关键词进行分词处理之后,再设置为多个分词的 查询条件,如下代码这一部分 foreach (var wordInfo in words)
5.建立索引时 分词被索引时 不区分大小写,也就是 你在查询的时候 必须按照 指定的大小写 查询,如果想解决这个大小写问题:建立索引时 多建一个统一小写的filed吧,查询时 也用小写后的关键词进行分词
//单字段查询 //QueryParser qp = new QueryParser(Lucene.Net.Util.Version.LUCENE_30, "title", analyzer); //Query mQuery = qp.Parse(keyword); //2008年底 //多字段查询一 //var fields = new Dictionary<string, string>() { { "title", keyword }, { "body", keyword } }; //var fieldsOccur = new Dictionary<string, Occur>() { { "title", Occur.SHOULD }, { "body", Occur.SHOULD } }; //if (!string.IsNullOrEmpty(lang)) //{ // fields.Add("lang",lang); // fieldsOccur.Add("lang", Occur.MUST); //} //Query mQuery = MultiFieldQueryParser.Parse(Version.LUCENE_30, fields.Select(x => x.Value).ToArray(), fields.Select(x => x.Key).ToArray(), fieldsOccur.Select(x=>x.Value).ToArray(), analyzer); //多字段查询二[弊端 只支持单个关键词输入] //MultiFieldQueryParser parser = new MultiFieldQueryParser(Version.LUCENE_30, new string[] { "lang", "title", "body" }, analyzer, new Dictionary<string, float>() { { "lang", 3 }, { "title", 2 }, { "body", 1 } }); //parser.DefaultOperator = QueryParser.Operator.AND; //Query mQuery = parser.Parse(keyword); //多字段查询三 Query query1 = null; var mQuery = new BooleanQuery(); //分类查询 query1 = new TermQuery(new Term("type", type)); mQuery.Add(query1, Occur.MUST); //通配符查询 if (string.IsNullOrEmpty(lang)) lang = "*"; query1 = new WildcardQuery(new Term("lang", lang)); mQuery.Add(query1, Occur.MUST); //范围查询 var beginTime = Convert.ToInt64(TimeHelper.ToUnixTimeStamp(DateTime.Now.AddYears(-3))); var endTime = Convert.ToInt64(TimeHelper.ToUnixTimeStamp(DateTime.Now.AddYears(0))); query1 = NumericRangeQuery.NewLongRange("time", 1, beginTime, endTime, true, true); mQuery.Add(query1, Occur.MUST); var keyQuery = new BooleanQuery(); #region 方法一 (查询结果较精准,最优结果在前面,结果较多) foreach (var wordInfo in words) { var word = wordInfo.Word; //标题查询 query1 = new TermQuery(new Term("title", word)) { Boost = 200 }; keyQuery.Add(query1, Occur.SHOULD); //内容查询 query1 = new TermQuery(new Term("body", word)) { Boost = 2 }; keyQuery.Add(query1, Occur.SHOULD); //支持小写 TermQuery不会对你提供的fieldValue做任何处理,所以部分可能查不出来,这里让其支持小写 以便能查出结果 word = word.ToLower(); //标题查询 query1 = new TermQuery(new Term("title", word)) { Boost = 200 }; keyQuery.Add(query1, Occur.SHOULD); //内容查询 query1 = new TermQuery(new Term("body", word)) { Boost = 2 }; keyQuery.Add(query1, Occur.SHOULD); } #endregion #region 方法二 查询结果较精准,结果较少 //query1 = new QueryParser(Version.LUCENE_30, "title", analyzer).Parse(keyword); //query1.Boost = 200; //keyQuery.Add(query1, Occur.SHOULD); //query1 = new QueryParser(Version.LUCENE_30, "body", analyzer).Parse(keyword); //query1.Boost = 2; //keyQuery.Add(query1, Occur.SHOULD); #endregion #region 方法三 查询结果较精准,结果较少 //MultiFieldQueryParser parser = new MultiFieldQueryParser(Version.LUCENE_30, new string[] { "title", "body" }, analyzer, new Dictionary<string, float>() { { "title", 200 }, { "body", 2 } }); ////parser.DefaultOperator = QueryParser.Operator.OR; //query1 = parser.Parse(keyword); //keyQuery.Add(query1, Occur.SHOULD); #endregion #region 方法四 查询结果较精准,结果较少 用时超级长 6000条数据12秒(不准确,单元测试的速度 不能为准,实际很快的) //MultiFieldQueryParser parser = new MultiFieldQueryParser(Version.LUCENE_30, new string[] { "title", "body" }, analyzer, new Dictionary<string, float>() { { "title", 200 }, { "body", 2 } }); ////parser.DefaultOperator = QueryParser.Operator.OR; //query1 = parser.Parse(keyword); //mQuery.Add(query1, Occur.MUST); #endregion if(keyQuery.Any())mQuery.Add(keyQuery,Occur.MUST); TopDocs tds = searcher.Search(mQuery, 10);
下面转自:http://iamyida.iteye.com/blog/2194651
首先来学习用下TermQuery,这是最简单的一个Query实现,即查询索引文档中是否包含了指定的Term,Lucene官方API注释里是这样说的:
- public class TermQuery
- extends Query
- A Query that matches documents containing a term. This may be combined with other terms with a BooleanQuery.
那什么又是Term呢?还是看看官方给的解释吧
- public final class Term
- extends Object
- implements Comparable<Term>
- A Term represents a word from text. This is the unit of search. It is composed of two elements, the text of the word, as a string, and the name of the field that the text occurred in. Note that terms may represent more than words from text fields, but also things like dates, email addresses, urls, etc.
一个Term表示着一个来自文本中的一个单词(因为老外眼里只有单词,没有中文,在中文里word可以理解为一个词语),它是一个搜索单元,它有两部分组成,单词文本和域的名称,后面着重提醒了我们,term不仅仅是文本中单词,还可以是日期,email地址,url链接等等。一句话,Term就是分词过后的一个个词组。
使用的时候new TermQuery(Term term)即可,Term对象的构造器有两个参数,fieldName和fieldValue,如:
new Term("title","Java");即表示在title域里查询包含Java的,示例代码如下:
- Query query = new TermQuery(new Term(fieldName,queryString));
当然你也可以通过QueryParser类来创建我们的Query对象,如:
- QueryParser parser = new QueryParser(fieldName, new AnsjAnalyzer());
- Query query = parser.parse(queryString);
但两者还是有点小小区别的,QueryParser会经过分词器,会使用分词器把我们的queryString(用户输入的查询关键字)进行分词,我们都知道分词器一般都会先把文本先全部转成小写然后去掉停用词等等一系列操作,而TermQuery则不会,而是直接根据用户提供的fieldValue去分词后的Term里查找的,我们知道分词后索引里存储的Term的value肯定都是小写的,如果我们提供的fieldVlue是大写的,肯定是查询不到的,这是大家比较容易忽略的,举个例子吧,比如你的文本里包含了“I服了U”这个网络词汇的,默认肯定是不会把它当成一个词语,如果使用了ansj分词器并把这个词语配置到自定义词典里,如:
那么分词后我们索引里的term中存储的应该是i服了u,而不是I服了U,所以如果你们使用I服了U作为搜索关键字来搜索,是搜不到任何结果的,这时你就蒙圈了,我不是已经配置了自定义词典了吗?为什么找不到?为了避免你们犯这种错误,特此提醒,TermQuery不会对你提供的fieldValue做任何处理,而QueryParser会,这也是为什么QueryParser构建的时候需要用户提供Analyzer对象而TermQuery不需要的原因。
TermQuery使用起来很简单,使用时候该注意的问题我也说过了,就说这么多,打完收工!希望对你们学习Lucene有所帮助。