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

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

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

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

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

 

代码 4.3.2.1using System;using System.Collections.Generic;using Lucene.Net.Analysis;using Lucene.Net.Analysis.Standard;using Lucene.Net.Documents;using Lucene.Net.Index;using Lucene.Net.QueryParsers;using Lucene.Net.Search;using NUnit.Framework;

namespace Test{    [TestFixture]public class StandardAnalyzerCaseTest    {/// <summary>/// 执行测试的入口/// </summary>        [Test]public void SearcherTest()        {            Index();            List<string> list = new List<string>() { "测试" };for (int i = 0; i < list.Count; i++)            {                Console.WriteLine("搜索词:" + list[i]);                Console.WriteLine("结果:");                Searcher(list[i]);                Console.WriteLine("-----------------------------------");            }        }

/// <summary>/// 搜索/// </summary>/// <param name="querystring">搜索输入</param>        private void Searcher(string querystring)        {            Analyzer analyzer = new StandardAnalyzer();            IndexSearcher searcher = new IndexSearcher("IndexDirectory");            QueryParser parser = new QueryParser("content", analyzer);            Query query = parser.Parse(querystring);//输出我们要查看的表达式            Console.WriteLine(query.ToString());             Hits hits = searcher.Search(query);for (int i = 0; i < hits.Length(); i++)            {                Document doc = hits.Doc(i);                Console.WriteLine(doc.Get("title"));            }        }

/// <summary>/// 索引数据/// </summary>        private void Index()        {            Analyzer analyzer = new StandardAnalyzer();            IndexWriter writer = new IndexWriter("IndexDirectory", analyzer, true);            AddDocument(writer, "测试", @"测定是123123ab阿布");            AddDocument(writer, "测试测", @"测试搜索真的是不是 ");            AddDocument(writer, "来测试", @"好好测试山");            AddDocument(writer, "测试系统", @"测试样例");            writer.Optimize();            writer.Close();        }/// <summary>/// 添加文档/// </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)        {            Document document = new Document();            document.Add(new Field("title", title, Field.Store.YES, Field.Index.TOKENIZED));            document.Add(new Field("content", content, Field.Store.YES, Field.Index.TOKENIZED));            writer.AddDocument(document);        }    }}

 

先准备好代码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。

代码 4.3.3.1        /// <summary>/// 执行测试的入口/// </summary>        [Test]public void SearcherTest()        {            Index();            List<string> list = new List<string>() { "真是" };for (int i = 0; i < list.Count; i++)            {                Console.WriteLine("搜索词:" + list[i]);                Console.WriteLine("结果:");                Searcher(list[i]);                Console.WriteLine("-----------------------------------");            }        }

/// <summary>/// 搜索/// </summary>/// <param name="querystring">搜索输入</param>        private void Searcher(string querystring)        {            Analyzer analyzer = new StandardAnalyzer();

//构造BooleanQuery            QueryParser parser = new QueryParser("content", analyzer);            BooleanQuery bquery = new BooleanQuery();            TokenStream ts = analyzer.TokenStream(null, new StringReader(querystring));            Lucene.Net.Analysis.Token token;while ((token = ts.Next()) != null)            {                Query query = parser.Parse(token.TermText());                bquery.Add(query, BooleanClause.Occur.MUST);            }//构造完成

IndexSearcher searcher = new IndexSearcher("IndexDirectory");

//Query query = parser.Parse(querystring);//输出我们要查看的表达式            Console.WriteLine(bquery.ToString());            Hits hits = searcher.Search(bquery);for (int i = 0; i < hits.Length(); i++)            {                Document doc = hits.Doc(i);                Console.WriteLine(doc.Get("title"));            }        }

 

测试:

搜索词:真是
结果:
+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的运算符的话,那只有这么两个也太单调了。实际上它还有其它运算符。

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

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

 

什么问题?下一节再讲。

时间: 2024-11-05 22:01:51

Lucene.Net 2.3.1开发介绍 —— 四、搜索(二)的相关文章

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

原文:Lucene.Net 2.3.1开发介绍 -- 四.搜索(一) 既然是内容筛选,或者说是搜索引擎,有索引,必然要有搜索.搜索虽然与索引有关,那也只是与索引后的文件有关,和索引的程序是无关的,因此,搜索和索引一般是分开部署.简单地说,就是一个应用程序(桌面程序)来索引,一个WEB程序来实现搜索.当然,为了测试的时候简单,这里还是使用NUnit的方式运行.搜索讲完后,将会简单介绍单机搜索引擎如何部署. 4.1 搜索与什么有关 搜索与什么有关呢?即使没有看过前面的文章,那么现在来随便猜一猜. 首

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

原文:Lucene.Net 2.3.1开发介绍 -- 四.搜索(三) Lucene有表达式就有运算符,而运算符使用起来确实很方便,但另外一个问题来了. 代码 4.3.4.1Analyzer analyzer = new StandardAnalyzer();QueryParser parser = new QueryParser("title", analyzer);Query query = parser.Parse(@":");Console.WriteLine

Lucene.Net 2.3.1开发介绍 —— 二、分词(四)

原文:Lucene.Net 2.3.1开发介绍 -- 二.分词(四) 2.1.2 可以使用的内置分词   简单的分词方式并不能满足需求.前文说过Lucene.Net内置分词中StandardAnalyzer分词还算比较实用(见1.1.2小节).StandardAnalyzer为什么能满足我们的部分需求,而它又有哪些不足呢?看分词的好坏还是要从效果说起.简单的说,在中英文混合的情况下,StandardAnalyzer会把英文按空格拆,而中文则按单字拆.因为中文是按单字拆,所以对分词的准确性起到了干

Lucene.Net 2.3.1开发介绍 —— 三、索引(四)

原文:Lucene.Net 2.3.1开发介绍 -- 三.索引(四) 4.索引对搜索排序的影响   搜索的时候,同一个搜索关键字和同一份索引,决定了一个结果,不但决定了结果的集合,也确定了结果的顺序.那个这个结果是怎么得出来的?这个顺序又是怎么排的呢?这两个问题不是本节讨论的重点,但是这两个问题却关系到本节要讨论的,索引对结果的影响问题.在不使用字段排序的情况下,Lucene.Net默认是按文档的得分来排序的,这个公式看着很复杂,感觉像是大学时高数书上的那些个公式,其实说清楚了也简单. 关于文档

Lucene.Net 2.3.1开发介绍 —— 三、索引(五)

原文:Lucene.Net 2.3.1开发介绍 -- 三.索引(五) 话接上篇,继续来说权重对排序的影响.从上面的4个测试,只能说是有个直观的理解了."哦,是!调整权重是能影响排序了,但是好像没办法来分析到底怎么调啊!".似乎是这样,现在需要把问题放大,加大索引的内容.到博客园新闻区,用zzk找了4篇内容包含"测试"的文章.代码变成 2.1.5 代码2.1.5  1using System;  2using System.Collections.Generic;  

Lucene.Net 2.3.1开发介绍 —— 三、索引(三)

原文:Lucene.Net 2.3.1开发介绍 -- 三.索引(三) 3.Field配置所产生的效果  索引数据,简单的代码,只要两个方法就搞定了,而在索引过程中用到的一些类里最简单,作用也不小的就是Field,接下来看看Field的各项设置都会有什么样的效果. 代码 3.1   Code 1/**//// <summary> 2/// 索引数据 3/// </summary> 4private void Index() 5{ 6    Analyzer analyzer = ne

Lucene.Net 2.3.1开发介绍 —— 三、索引(二)

原文:Lucene.Net 2.3.1开发介绍 -- 三.索引(二) 2.索引中用到的核心类 在Lucene.Net索引开发中,用到的类不多,这些类是索引过程的核心类.其中Analyzer是索引建立的基础,Directory是索引建立中或者建立好存储的介质,Document和Field类是逻辑结构的核心,IndexWriter是操作的核心.其他类的使用都被隐藏掉了,这也是为什么Lucene.Net使用这么方便的原因.   2.1 Analyzer 前面已经对Analyzer进行了很详细的讲解,A

Lucene.Net 2.3.1开发介绍 —— 二、分词(五)

原文:Lucene.Net 2.3.1开发介绍 -- 二.分词(五) 2.1.3 二元分词   上一节通过变换查询表达式满足了需求,但是在实际应用中,如果那样查询,会出现另外一个问题,因为,那样搜索,是只要出现这个字,不管它出现在什么位置.这就产生了上一小节开头讲的,对准确性产生了极大干扰.比如,如果有一段这样的话:"这是一个英雄!他有无法用词汇形容的孤单,但是他并没有用言语来表达."这句话包含了"英 语 单 词"这四个字,但是却和"英语单词"一

Lucene.Net 2.3.1开发介绍 —— 简介

原文:Lucene.Net 2.3.1开发介绍 -- 简介          Lucene.Net是Lucene在dot net平台上的移植版本.它的功能与Lucene一样,都是用来提供一组API,让我们能快速开发自己的搜索引擎,当然,是全文搜索.它不是一个程序,拿到它并不能立刻运行,你必须自己实现逻辑过程.这是一个和.Net Framework一样的框架.Lucene是用Java写的,尔后衍生出Nutch,接着又衍生出Hadoop.这些可以说和Lucene没有内在联系,但是它们可以扩充Luce