Lucene.Net 2.3.1开发介绍 —— 四、搜索(二)

释放双眼,带上耳机,听听看~!

原文:Lucene.Net 2.3.1开发介绍 —— 四、搜索(二)

**4.3 表达式
**用户搜索,只会输入一个或几个词,也可能是一句话。输入的语句是如何变成搜索条件的上一篇已经略有提及。

4.3.1 观察表达式
在研究表达式之前,一定要知道,任何一个Query都会对于一个表达式。不光可以通过Query构造表达式,还可以通过拼接字符串构造。这里说的观察表达式是指,用Query完成查询语句后,用ToString()方法输出Query的表达式。很简单是吧,呵呵。

**4.3.2 表达式的与或非
**“与或非”让我想起上学的时候学的门电路 ==#。先动手看看什么是与或非。

 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
1代码 4.3.2.1using System;  
2using System.Collections.Generic;  
3using Lucene.Net.Analysis;  
4using Lucene.Net.Analysis.Standard;  
5using Lucene.Net.Documents;  
6using Lucene.Net.Index;  
7using Lucene.Net.QueryParsers;  
8using Lucene.Net.Search;  
9using NUnit.Framework;  
10namespace Test  
11{  
12    [TestFixture]  
13public class StandardAnalyzerCaseTest  
14    {  
15/// <summary>/// 执行测试的入口  
16/// </summary>        [Test]  
17public void SearcherTest()  
18        {  
19            Index();  
20            List<string> list = new List<string>() { "测试" };  
21for (int i = 0; i < list.Count; i++)  
22            {  
23                Console.WriteLine("搜索词:" + list[i]);  
24                Console.WriteLine("结果:");  
25                Searcher(list[i]);  
26                Console.WriteLine("-----------------------------------");  
27            }  
28        }  
29/// <summary>/// 搜索  
30/// </summary>/// <param name="querystring">搜索输入</param>        private void Searcher(string querystring)  
31        {  
32            Analyzer analyzer = new StandardAnalyzer();  
33            IndexSearcher searcher = new IndexSearcher("IndexDirectory");  
34            QueryParser parser = new QueryParser("content", analyzer);  
35            Query query = parser.Parse(querystring);  
36//输出我们要查看的表达式            Console.WriteLine(query.ToString());  
37            Hits hits = searcher.Search(query);  
38for (int i = 0; i < hits.Length(); i++)  
39            {  
40                Document doc = hits.Doc(i);  
41                Console.WriteLine(doc.Get("title"));  
42            }  
43        }  
44/// <summary>/// 索引数据  
45/// </summary>        private void Index()  
46        {  
47            Analyzer analyzer = new StandardAnalyzer();  
48            IndexWriter writer = new IndexWriter("IndexDirectory", analyzer, true);  
49            AddDocument(writer, "测试", @"测定是123123ab阿布");  
50            AddDocument(writer, "测试测", @"测试搜索真的是不是 ");  
51            AddDocument(writer, "来测试", @"好好测试山");  
52            AddDocument(writer, "测试系统", @"测试样例");  
53            writer.Optimize();  
54            writer.Close();  
55        }  
56/// <summary>/// 添加文档  
57/// </summary>/// <param name="writer">维护文档管理器</param>/// <param name="title">标题</param>/// <param name="content">内容</param>/// <param name="tag">tag</param>/// <param name="boost">tag的boost</param>        void AddDocument(IndexWriter writer, string title, string content)  
58        {  
59            Document document = new Document();  
60            document.Add(new Field("title", title, Field.Store.YES, Field.Index.TOKENIZED));  
61            document.Add(new Field("content", content, Field.Store.YES, Field.Index.TOKENIZED));  
62            writer.AddDocument(document);  
63        }  
64    }  
65}
66

 

先准备好代码4.3.2.1,OK,现在测试。结果输出:

搜索词:测试
结果:
content:"测 试"
测试系统
来测试
测试测

第三行,就是表达式。这个表达式不知道是什么意思?输入了“测试”这两个字进行搜索,怎么会变成 “content:"测 试"”呢?可以看出,“测试”中间空了一个空格,还多了一个content。“测试”中间有空格不难理解,是分词器对它进行拆分的结果。至于content,这个需要把目光转到QueryParser类上去,在构造QueryParser类的时候,就加了这么个参数。这个是表面要搜索哪个字段。为了验证这个想法,现在把“测试”换成英文“ab”,把content换成title.

也就是替换以下两句:

List<string> list = new List<string>() { "ab" };         //在方法SearcherTest中
QueryParser parser = new QueryParser("title", analyzer);     //在方法Searcher中

现在再测试一下:

搜索词:ab
结果:
title:ab

看到了,果然是这样的。

现在把查询的字段还是换成content,然后把关键字换成“真是”。

搜索词:真是
结果:
content:"真 是"

结果出来了,也印证了上面的想法。但是明明有一条记录同时包含这两个字了,为什么没有搜索到呢?是不是加个空格就可以了呢?把“真的”变成“真 的”。再来试试。

搜索词:真 是
结果:
content:真 content:是
测试测
测试

真神奇,表达式变掉了,而且只包含一个“是”但是没有“真”的记录也出来了。这表明什么?这表明现在的语句就是或的关系,只要满足包含“是”或者包含“真”就可以搜索到了。

(以上内容前面章节有提到,现在开始进入正式气氛。——Birdshover)

但是我现在就想要搜索同时包含两个字的记录怎么办呢?嘿嘿,在每个字前面加个“+”号试试。关键词变成“+真 +是”看看结果:

搜索词:+真 +是
结果:
+content:真 +content:是
测试测

那现在我要搜索包含“是”但是不包含“真”的结果,怎么办?试试这个语句“-真 +是”。

搜索词:-真 +是
结果:
-content:真 +content:是
测试

与或非终于被我们折腾完了。

总结下关系就是:

a & b  =>   +a +b
a || b  =>   a    b
a  !b   =>   +a  -b
4.3.3 如何用Query构造与或非

Lucene.Net框架提供的Query也是可以完成与或非运算的,一般用BooleanQuery来构造。怎么构造?现在对搜索部分代码进行变动,变成4.3.3.1。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
1代码 4.3.3.1/// &lt;summary&gt;/// 执行测试的入口  
2/// &lt;/summary&gt;        [Test]  
3public void SearcherTest()  
4        {  
5            Index();  
6            List&lt;string&gt; list = new List&lt;string&gt;() { &quot;真是&quot; };  
7for (int i = 0; i &lt; list.Count; i++)  
8            {  
9                Console.WriteLine(&quot;搜索词:&quot; + list[i]);  
10                Console.WriteLine(&quot;结果:&quot;);  
11                Searcher(list[i]);  
12                Console.WriteLine(&quot;-----------------------------------&quot;);  
13            }  
14        }  
15/// &lt;summary&gt;/// 搜索  
16/// &lt;/summary&gt;/// &lt;param name=&quot;querystring&quot;&gt;搜索输入&lt;/param&gt;        private void Searcher(string querystring)  
17        {  
18            Analyzer analyzer = new StandardAnalyzer();  
19//构造BooleanQuery            QueryParser parser = new QueryParser(&quot;content&quot;, analyzer);  
20            BooleanQuery bquery = new BooleanQuery();  
21            TokenStream ts = analyzer.TokenStream(null, new StringReader(querystring));  
22            Lucene.Net.Analysis.Token token;  
23while ((token = ts.Next()) != null)  
24            {  
25                Query query = parser.Parse(token.TermText());  
26                bquery.Add(query, BooleanClause.Occur.MUST);  
27            }  
28//构造完成            IndexSearcher searcher = new IndexSearcher(&quot;IndexDirectory&quot;);  
29//Query query = parser.Parse(querystring);  
30//输出我们要查看的表达式            Console.WriteLine(bquery.ToString());  
31            Hits hits = searcher.Search(bquery);  
32for (int i = 0; i &lt; hits.Length(); i++)  
33            {  
34                Document doc = hits.Doc(i);  
35                Console.WriteLine(doc.Get(&quot;title&quot;));  
36            }  
37        }
38

 

测试:

搜索词:真是
结果:
+content:真 +content:是
测试测

构造出与的表达式了。把BooleanQuery的Add方法第二个参数换成BooleanClause.Occur.SHOULD,

bquery.Add(query, BooleanClause.Occur.SHOULD);

这个就是或:

搜索词:真是
结果:
content:真 content:是
测试测
测试

而换成 bquery.Add(query, BooleanClause.Occur.MUST_NOT);这个就是非了:

搜索词:真是
结果:
-content:真 -content:是

4.3.4 其它特使符号

如果形容"+-"为Lucene.Net的运算符的话,那只有这么两个也太单调了。实际上它还有其它运算符。

+-!():^[]{}~*?

上面的字符都是它的运算符号,这么多运算符用起来很方便。但是也就出现另外一个问题。

 

什么问题?下一节再讲。

给TA打赏
共{{data.count}}人
人已打赏
安全运维

OpenSSH-8.7p1离线升级修复安全漏洞

2021-10-23 10:13:25

安全运维

设计模式的设计原则

2021-12-12 17:36:11

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索