1:Lucene
Lucene是一个全文搜索框架,而不是应用产品。因此它并不像www.baidu.com 或者google Desktop那么拿来就能用,它只是提供了一种工具让你能实现这些产品。
2:Pangu分词
盘古分词是一个中英文分词组件。
借用以上两个组件可以对中文分词实现全文搜索。
先说下大概概念
//一、Document //Document:文档对象,是一条原始的数据 //二、Field //如果一个字段要显示到最终的结果中,那么一定要存储,否则就不存储 //如果要根据这个字段进行搜索,那么这个字段就必须创建索引。 //如何确定一个字段是否需要分词? //前提是这个字段首先要创建索引。然后如果这个字段的值是不可分割的,那么就不需要分词。例如:ID //DoubleField、FloatField、IntField、LongField、StringField、TextField这些子类一定会被创建索引,但是不会被分词,而且不一定会被存储到文档列表。要通过构造函数中的参数Store来指定:如果Store.YES代表存储,Store.NO代表不存储 //TextField即创建索引,又会被分词。StringField会创建索引,但是不会被分词。 //StoreField一定会被存储,但是一定不创建索引 //三、Directory //FSDirectory:文件系统目录,会把索引库指向本地磁盘。 //特点:速度略慢,但是比较安全 //RAMDirectory:内存目录,会把索引库保存在内存。 //特点:速度快,但是不安全 //四、Analyzer(分词器类) 若有中文 需要第三方类库对中文进行分词 如pangu分词 //提供分词算法,可以把文档中的数据按照算法分词 //五、IndexWriterConfig(索引写出器配置类) //1) 设置配置信息:Lucene的版本和分词器类型 //2)设置是否清空索引库中的数据 //六、IndexWriter(索引写出器类) //索引写出工具,作用就是 实现对索引的增(创建索引)、删(删除索引)、改(修改索引) //可以一次创建一个,也可以批量创建索引 //核心API //5.2.2.1 QueryParser(查询解析器) //1)QueryParser(单一字段的查询解析器) //2)MultiFieldQueryParser(多字段的查询解析器) //5.2.2.2 Query(查询对象,包含要查询的关键词信息) //1)通过QueryParser解析关键字,得到查询对象 //2)自定义查询对象(高级查询) //我们可以通过Query的子类,直接创建查询对象,实现高级查询(后面详细讲) //5.2.2.3 IndexSearch(索引搜索对象,执行搜索功能) //IndexSearch可以帮助我们实现:快速搜索、排序、打分等功能。 //IndexSearch需要依赖IndexReader类 //查询后得到的结果,就是打分排序后的前N名结果。N可以通过第2个参数来指定: //5.2.2.4 TopDocs(查询结果对象) //通过IndexSearcher对象,我们可以搜索,获取结果:TopDocs对象 //在TopDocs中,包含两部分信息: //int totalHits :查询到的总条数 //ScoreDoc[] scoreDocs : 得分文档对象的数组 //5.2.2.5 ScoreDoc(得分文档对象) //ScoreDoc是得分文档对象,包含两部分数据: //int doc :文档的编号----lucene给文档的一个唯一编号 //float score :文档的得分信息 //拿到编号后,我们还需要根据编号来获取真正的文档信息
上代码:
1:接口:
public interface IDBService<TContext> where TContext : Microsoft.EntityFrameworkCore.DbContext { TContext Context { get; } } } //为泛型方法封装的。泛型方法里面实现的和搜索类实现的一样。 public interface IService<T> { List<T> QueryToList(int limit); List<T> QueryToList(int start, int end); List<T> QueryToList(string txt); List<T> QueryAll(); T QuerySignle(string guid); T QuerySignle(int pk_id); }
2:搜索类:
using System;
using System.Collections.Generic;
using System.Text;
using LuceneCore.Respority;
using LuceneCore.DB;
using Lucene.Net.Store;
using LuceneCore.Util;
using System.Linq;
namespace LuceneCore.Respority
{
class DbContextService<TDbContext> : IDBService<TDbContext> where TDbContext : Microsoft.EntityFrameworkCore.DbContext
{
public TDbContext Context { get; }
private List<Type> listType = new List<Type>();
//private static FSDirectory dir = FSDirectory.Open("");
private Lucene.Net.Index.IndexWriter writer = null;// new Lucene.Net.Index.IndexWriter(dir, new Lucene.Net.Analysis.PanGu.PanGuAnalyzer(), Lucene.Net.Index.IndexWriter.MaxFieldLength.LIMITED);
private Lucene.Net.Index.IndexReader reader = null;
public DbContextService(TDbContext _Context)
{
Context = _Context;
foreach (System.Reflection.PropertyInfo pro in Context.GetType().GetProperties())
{
if (pro.PropertyType.GenericTypeArguments != null && pro.PropertyType.GenericTypeArguments.Length > 0)
{
listType.Add(pro.PropertyType.GenericTypeArguments[0]);
}
}
}
public void Test<T>(T t)
{
CreateIndexWriter(@"C:\Users\FanLin\Desktop\index");
var list = new List<T>();
list.Add(t);
CreateIndex(list);
QueryByKeyWord<T>("搜索", false, null, 100, null, "NAME");
var query1 = CreateQuery<T,Lucene.Net.Search.TermQuery, Util.Attributes.TermQueryAttribute>("搜索");
var query = CreateBooleanQuery((query1, Lucene.Net.Search.Occur.SHOULD));
QueryBySpecidQuery(query);
}
/// <summary>
/// 创建IndexWriter和IndexReader对象
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
public (Lucene.Net.Index.IndexWriter, Lucene.Net.Index.IndexReader) CreateIndexWriter(string filePath)
{
FSDirectory dir = FSDirectory.Open(filePath);
if (writer == null)
{
writer = new Lucene.Net.Index.IndexWriter(dir, new Lucene.Net.Analysis.PanGu.PanGuAnalyzer(), Lucene.Net.Index.IndexWriter.MaxFieldLength.LIMITED);
writer.MergeFactor = 100;//控制多个segment合并的频率,默认10
writer.UseCompoundFile = true;//创建符合文件 减少索引文件数量
}
//var directory = System.IO.Directory.CreateDirectory(filePath);
if (reader == null)
{
reader = Lucene.Net.Index.IndexReader.Open(dir, false);
}
return (writer, reader);
}
/// <summary>
/// 提交
/// </summary>
private void CommitIndexWriter()
{
if (writer == null)
return;
writer.Commit();
}
//清除
private void FlushIndexWriter()
{
if (writer == null)
return;
writer.Flush(true, true, true);
}
/// <summary>
/// 关闭
/// </summary>
private void CloseIndexWriter()
{
if (writer == null)
return;
writer.Flush(true, true, true);
}
/// <summary>
/// 创建索引
/// </summary>
public void CreateIndex<T>(IEnumerable<T> tList)
{
// var config = new IndexWriterConfig(Lucene.Net.Util.LuceneVersion.LUCENE_48, _analyzer);
if (writer == null) return;
// 遍历实体集,添加到索引库
foreach (var entity in tList)
{
this.CreateIndex(entity);
}
this.CommitIndexWriter();
this.CloseIndexWriter();
}
/// <summary>
/// 创建索引
/// </summary>
private void CreateIndex<T>(T tSignal)
{
if (writer == null) return;
if (writer.NumDocs() <= 0)
{
writer.AddDocument(tSignal.ToDocument());
}
else
{
this.UpdateIndex(tSignal);
}
//if (cmit) this.CommitIndexWriter(true);
}
/// <summary>
/// 增加索引
/// </summary>
private void UpdateIndex<T>(T t)
{
if (writer == null) return;
if (reader == null) return;
//如果 有先删除
writer.UpdateDocument(new Lucene.Net.Index.Term(t.GetCustomAttributeColumn_KeyAndValue<T, System.ComponentModel.DataAnnotations.KeyAttribute>().field, t.GetCustomAttributeColumn_KeyAndValue<T, System.ComponentModel.DataAnnotations.KeyAttribute>().txt), t.ToDocument());
}
/// <summary>
/// 批量修改索引
/// </summary>
/// <param name="ts"></param>
public void UpdateIndexEnumerable<T>(IEnumerable<T> ts)
{
//如果 有先删除
foreach (var t in ts)
{
UpdateIndex(t);
}
this.CommitIndexWriter();
this.CloseIndexWriter();
}
/// <summary>
/// 删除索引
/// </summary>
private void DeleteIndex<T>(T t)
{
if (reader == null) return;
reader.DeleteDocuments(new Lucene.Net.Index.Term(t.GetCustomAttributeColumn_KeyAndValue<T, System.ComponentModel.DataAnnotations.KeyAttribute>().field, t.GetCustomAttributeColumn_KeyAndValue<T, System.ComponentModel.DataAnnotations.KeyAttribute>().txt));
}
/// <summary>
/// 批量删除索引
/// </summary>
public void DeleteIndex<T>(IEnumerable<T> tEnum)
{
if (reader == null) return;
foreach (var t in tEnum)
{
DeleteIndex(t);
}
this.CommitIndexWriter();
this.CloseIndexWriter();
}
/// <summary>
/// 删除所有索引
/// </summary>
public void DeleteAllIndex()
{
if (writer == null) return;
writer.DeleteAll();
}
/// <summary>
/// 根据关键字来查询
/// </summary>
/// <param name="keyWord">查询关键字</param>
/// <param name="isMulti">是否对多字段查询</param>
/// <param name="filter">过滤条件</param>
/// <param name="n">需要查出多少条</param>
/// <param name="sort">排序规则</param>
/// <param name="filterColumn">对哪些字段做查询</param>
/// <returns></returns>
public IEnumerable<T> QueryByKeyWord<T>(string keyWord, bool isMulti, Lucene.Net.Search.Filter filter, int n, Lucene.Net.Search.Sort sort, params string[] filterColumn)
{
// 索引搜索工具
//IndexSearch可以帮助我们实现:快速搜索、排序、打分等功能。
//IndexSearch需要依赖IndexReader类
Lucene.Net.Search.IndexSearcher searcher = new Lucene.Net.Search.IndexSearcher(reader);
//关键字
//string kwyWord = "";
Lucene.Net.Search.Query query = null;
//参数分别表示:版本号 对哪个字段分词查询 分词器
//这是对单一字段做分词查询
//单一字段查询 或者多个字段查询
if (isMulti && filterColumn.Length <= 1)
{
throw new ArgumentNullException(filter + "为null,请传入需要查询的字段");
}
if (!isMulti && filterColumn.Length > 1)
{
throw new ArgumentNullException(filter + "当前不是多字段查询,只允许传入一个字段名称!");
}
Lucene.Net.QueryParsers.QueryParser queryParser = null;
if (!isMulti)
{
//对单字段做查询
queryParser = new Lucene.Net.QueryParsers.QueryParser(Lucene.Net.Util.Version.LUCENE_30, filterColumn[0], new Lucene.Net.Analysis.PanGu.PanGuAnalyzer());
//解析关键字
// query = queryParser.Parse(keyWord);
}
else
{
queryParser = new Lucene.Net.QueryParsers.MultiFieldQueryParser(Lucene.Net.Util.Version.LUCENE_30, filterColumn, new Lucene.Net.Analysis.PanGu.PanGuAnalyzer());
}
//解析关键字
query = queryParser.Parse(keyWord);
//query的分类
//返回100条数据
// TopDocs(查询结果对象)
//通过IndexSearcher对象,我们可以搜索,获取结果:TopDocs对象
//是否需要过滤和排序
Lucene.Net.Search.TopDocs topDocs = searcher.Search(query, 100);
IList<T> values = new List<T>();
//ScoreDoc是得分文档对象
foreach (Lucene.Net.Search.ScoreDoc sDoc in topDocs.ScoreDocs)
{
float score = sDoc.Score;
//拿到document
Lucene.Net.Documents.Document document = reader.Document(sDoc.Doc);
values.Add(document.ToEntity<T>());
//将document转换成entity
}
return values;
}
/// <summary>
/// 根据query查询
/// </summary>
/// <param name="query"></param>
private void QueryBySpecidQuery(Lucene.Net.Search.Query query)
{
// 索引搜索工具
//IndexSearch可以帮助我们实现:快速搜索、排序、打分等功能。
//IndexSearch需要依赖IndexReader类
if (query == null) return;
if (reader == null) return;
Lucene.Net.Search.IndexSearcher searcher = new Lucene.Net.Search.IndexSearcher(reader);
if (searcher == null) return;
//query的分类
//返回100条数据
// TopDocs(查询结果对象)
//通过IndexSearcher对象,我们可以搜索,获取结果:TopDocs对象
Lucene.Net.Search.TopDocs topDocs = searcher.Search(query, 100);
//ScoreDoc是得分文档对象
foreach (Lucene.Net.Search.ScoreDoc sDoc in topDocs.ScoreDocs)
{
int id = sDoc.Doc;
float score = sDoc.Score;
//拿到document
Lucene.Net.Documents.Document document = reader.Document(id);
//将document转换成entity
}
}
//TermQuery可以用“field:key”方式,例如“content:lucene”。
//BooleanQuery中‘与’用‘+’,‘或’用‘ ’,例如“content:java contenterl”。
//WildcardQuery仍然用‘?’和‘*’,例如“content:use*”。
//PhraseQuery用‘~’,例如“content:"中日"~5”。
//PrefixQuery用‘*’,例如“中*”。
//FuzzyQuery用‘~’,例如“content: wuzza ~”。
//RangeQuery用‘[]’或‘{}’,前者表示闭区间,后者表示开区间,例如“time:[20060101 TO 20060130]”,注意TO区分大小写。
//例如“标题或正文包括lucene,并且时间在20060101到20060130之间的文章” 可以表示为:“+ (title:lucene content:lucene) +time:[20060101 TO 20060130]”
/*
#region 特殊查询
/// <summary>
/// 单条匹配查询
/// </summary>
public void GetTermQuery(string content)
{
List<string> fids = GetCustomAttributeForQuery<Util.Attributes.TermQueryAttribute>();
if (fids != null && fids.Count() > 0)
{
Lucene.Net.Search.Query query = new Lucene.Net.Search.TermQuery(new Lucene.Net.Index.Term(fids[0], content));
}
}
/// <summary>
/// 通配符查询
/// </summary>
public void GetWildcardQuery(string charContent)
{
List<string> fids = GetCustomAttributeForQuery<Util.Attributes.WildcardQueryAttribute>();
if (fids != null && fids.Count() > 0)
{
Lucene.Net.Search.Query query = new Lucene.Net.Search.WildcardQuery(new Lucene.Net.Index.Term(fids[0], charContent));
}
//QueryLucene(query);
}
/// <summary>
/// 模糊查询
/// </summary>
public void GetFuzzyQuery(string content)
{
List<string> fids = GetCustomAttributeForQuery<Util.Attributes.FuzzyQueryAttribute>();
if (fids != null && fids.Count() > 0)
{
Lucene.Net.Search.Query query = new Lucene.Net.Search.FuzzyQuery(new Lucene.Net.Index.Term(fids[0], content));
}
//QueryLucene(query);
}
/// <summary>
/// 搜索两个单词距离指定间隔的数据
/// </summary>
public void GetPhraseQuery(int slop, string prv, string next)
{
Lucene.Net.Search.PhraseQuery query = new Lucene.Net.Search.PhraseQuery();
query.Slop = 5;
query.Add(new Lucene.Net.Index.Term("content ", prv));
query.Add(new Lucene.Net.Index.Term("content", next));
}
/// <summary>
/// 以指定字符开头
/// </summary>
public void GetPrefixQuery(string content)
{
Lucene.Net.Search.PrefixQuery query = new Lucene.Net.Search.PrefixQuery(new Lucene.Net.Index.Term("content ", content));
}
#endregion
*/
/// <summary>
/// 根据传入的特性查找定义了此特性的属性
/// </summary>
/// <typeparam name="Attr"></typeparam>
/// <returns></returns>
private static List<string> GetCustomAttributeForQuery<T, Attr>()
{
var pro = typeof(T).GetProperties().Where(x => x.IsDefined(typeof(Attr), false));
var list = pro.Select(x => x?.Name).ToList();
return list;
// var prop=
//return typeof(T).GetProperties().Select(x =>
//{
// if (x.IsDefined(typeof(Attr), false))
// {
// return x.Name;
// }
// else
// {
// return null;
// }
//}).ToList();
}
/// <summary>
/// 创建组合查询
/// </summary>
/// <param name="querysAndoccurs">传入需要进行组合的查询方式和逻辑关联</param>
/// <returns></returns>
public Lucene.Net.Search.Query CreateBooleanQuery(params (Lucene.Net.Search.Query query, Lucene.Net.Search.Occur occur)[] querysAndoccurs)
{
//Lucene.Net.Search.Query query = new Lucene.Net.Search.FuzzyQuery(new Lucene.Net.Index.Term("", ""));
//Lucene.Net.Search.Query query2 = Lucene.Net.Search.NumericRangeQuery.NewLongRange("", 0, 0, true, true);
Lucene.Net.Search.BooleanQuery bQuery = new Lucene.Net.Search.BooleanQuery();
//* 交集:Occur.MUST + Occur.MUST
//* 并集:Occur.SHOULD + Occur.SHOULD
//* 非:Occur.MUST_NOT
querysAndoccurs.ToList().ForEach(tuple =>
{
bQuery.Add(tuple.query, tuple.occur);
});
return bQuery;
}
/// <summary>
/// 创建指定的查询方式。只支持单个查询。
/// </summary>
/// <typeparam name="U">继承自Query的查询类。如WildcardQuery/PrefixQuery/FuzzyQuery/TermQuery四种等</typeparam>
/// <typeparam name="Attr">实体属性上定义的特性名称,表示其需要执行那种查询方式,若有多个则组合成组合查询</typeparam>
/// <param name="content">查询关键字</param>
/// <returns></returns>
public Lucene.Net.Search.Query CreateQuery<T, U, Attr>(string content) where U : Lucene.Net.Search.Query where Attr : Util.Attributes.SpecidQueryAttribute
{
var tp = typeof(U);
var name = tp.Name;
//Lucene.Net.Search.Query query1 = new Lucene.Net.Search.TermQuery(new Lucene.Net.Index.Term("", ""));
switch (name)
{
case "WildcardQuery":
case "PrefixQuery":
case "FuzzyQuery":
case "TermQuery":
return Activator.CreateInstance(typeof(U), new Lucene.Net.Index.Term(GetCustomAttributeForQuery<T,Attr>()[0], content)) as Lucene.Net.Search.Query;
}
throw new KeyNotFoundException("传入的泛型<U>不正确");
}
/// <summary>
/// 范围查询,包括数字范围或者查询两个字符串指定间隔的数据
/// </summary>
/// <typeparam name="U"></typeparam>
/// <param name="minOrprv">U为long/int/float/double时传入数字,表示范围,为string时传入前边的字符串</param>
/// <param name="maxOrnext">U为long/int/float/double时传入数字,表示范围,为string时传入后边的字符串</param>
/// <param name="whenString">U为string时传入前后的字符串,这个为两个字符串之间的间隔</param>
/// <returns></returns>
public Lucene.Net.Search.Query CreateQuery<T, U>(U minOrprv, U maxOrnext, int whenString = 0)
{
Lucene.Net.Search.Query query = null;
List<string> fids = GetCustomAttributeForQuery<T, Util.Attributes.NumericRangeQueryAttribute>();
if (fids != null && fids.Count() > 0)
{
switch (typeof(U).Name)
{
case "long":
case "Int64":
query = Lucene.Net.Search.NumericRangeQuery.NewLongRange(fids[0], long.Parse(minOrprv.ToString()), long.Parse(maxOrnext.ToString()), true, true);
break;
case "int":
case "Int32":
query = Lucene.Net.Search.NumericRangeQuery.NewIntRange(fids[0], int.Parse(minOrprv.ToString()), int.Parse(maxOrnext.ToString()), true, true);
break;
case "double":
query = Lucene.Net.Search.NumericRangeQuery.NewDoubleRange(fids[0], double.Parse(minOrprv.ToString()), double.Parse(maxOrnext.ToString()), true, true);
break;
case "float":
query = Lucene.Net.Search.NumericRangeQuery.NewFloatRange(fids[0], float.Parse(minOrprv.ToString()), float.Parse(maxOrnext.ToString()), true, true);
break;
case "string":
var pQuery = new Lucene.Net.Search.PhraseQuery();
pQuery.Slop = whenString;
pQuery.Add(new Lucene.Net.Index.Term(fids[0], minOrprv.ToString()));
pQuery.Add(new Lucene.Net.Index.Term(fids[0], maxOrnext.ToString()));
query = pQuery;
// query = new Lucene.Net.Search.MultiPhraseQuery();
break;
default:
//不允许的
throw new InvalidProgramException("传入参数<U>有误,仅允许Long/Float/Double/Int/String");
}
}
return query;
}
/// <summary>
/// 排序方式,如果要使用,需要添加SpecdSortAttribute
/// </summary>
/// <param name="t"></param>
/// <returns></returns>
public Lucene.Net.Search.Sort SetSort<T>(T t)
{
//需要拿字段和类型
//排序
Lucene.Net.Search.Sort sort = new Lucene.Net.Search.Sort(t.GetSortAttributeValue());//排序 哪个前哪个后
return sort;
}
/// <summary>
/// 过滤条件
/// </summary>
/// <returns></returns>
public Lucene.Net.Search.Filter SetFilter()
{
// Lucene.Net.Search.filter
return Lucene.Net.Search.NumericRangeFilter.NewIntRange("time", 20220112, 20220113, true, true);
}
}
}
3:扩展方法
public static class ModelExtison { /// <summary> /// 将实体转换成Document /// </summary> /// <typeparam name="T"></typeparam> /// <param name="t"></param> /// <returns></returns> public static Lucene.Net.Documents.Document ToDocument<T>(this T t) { Lucene.Net.Documents.Document doc = new Lucene.Net.Documents.Document(); foreach (var propertyInfo in t.GetType().GetProperties()) { var attr = propertyInfo.GetCustomAttributes(typeof(LuceneCore.Util.Attributes.LuceneDefineAttribute), false); if (attr != null) { if (attr.Length > 0) { foreach (LuceneCore.Util.Attributes.LuceneDefineAttribute customAttr in attr) { doc.Add(new Lucene.Net.Documents.Field(propertyInfo.Name, propertyInfo.GetValue(t) == null ? "" : propertyInfo.GetValue(t).ToString(), customAttr.Store, customAttr.Index)); } } else { var attrtmp = new LuceneCore.Util.Attributes.LuceneDefineAttribute(); doc.Add(new Lucene.Net.Documents.Field(propertyInfo.Name, propertyInfo.GetValue(t) == null ? "" : propertyInfo.GetValue(t).ToString(), attrtmp.Store, attrtmp.Index)); } } } return doc; } /// <summary> /// 将document转换为实体 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="document"></param> /// <returns></returns> public static T ToEntity<T>(this Lucene.Net.Documents.Document document) { T t = default(T); t = (T)Activator.CreateInstance(typeof(T)); foreach (System.Reflection.PropertyInfo pro in typeof(T).GetProperties()) { pro.SetValue(t, Convert.ChangeType(document.Get(pro.Name), pro.PropertyType)); } return t; } /// <summary> /// 返回标注了指定特性的字段和值 /// </summary> /// <typeparam name="T"></typeparam> /// <typeparam name="Attr"></typeparam> /// <param name="obj"></param> /// <returns></returns> public static (string field, string txt) GetCustomAttributeColumn_KeyAndValue<T,Attr>(this T obj) { foreach (System.Reflection.PropertyInfo pro in typeof(T).GetProperties()) { if (pro.IsDefined(typeof(Attr), false)) { var val = pro.GetValue(pro.Name); return (pro.Name, val == null ? "" : val.ToString()); } } return ("", ""); } /// <summary> /// 根据标注了排序特性的字段的类型返回排序类型 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="obj"></param> /// <returns></returns> public static Lucene.Net.Search.SortField[] GetSortAttributeValue<T>(this T obj) { Lucene.Net.Search.SortField[] tuples = null; Dictionary<Lucene.Net.Search.SortField, int> keyValuePairs = new Dictionary<Lucene.Net.Search.SortField, int>(); var defindSpecidAttr = typeof(T).GetProperties().Where(x => x.IsDefined(typeof(Util.Attributes.SpecidSortAttribute), true)); if (defindSpecidAttr != null && defindSpecidAttr.Count() > 0) { int index = 0; foreach (var item in defindSpecidAttr) { var attr = (Util.Attributes.SpecidSortAttribute)item.GetCustomAttributes(false).FirstOrDefault(x => x.GetType() == typeof(Util.Attributes.SpecidSortAttribute)); Lucene.Net.Search.SortField sortField = new Lucene.Net.Search.SortField(item.Name, item.PropertyType.GetSortFieldType(), attr.Desc);//降序 keyValuePairs.Add(sortField, attr.Order); tuples[index] = sortField; index++; } } tuples = keyValuePairs.OrderBy(x => x.Value).Select(x => x.Key).ToArray(); // tuples = tuples.OrderBy(x => x.Order); return tuples; } /// <summary> /// 具体根据某一类型返回具体数值 /// </summary> /// <param name="t"></param> /// <returns></returns> public static int GetSortFieldType(this Type t) { return t switch { _ when t.Name == "Int32" || t.Name == "int" => Lucene.Net.Search.SortField.INT, _ when t.Name == "Int64" || t.Name == "long" => Lucene.Net.Search.SortField.LONG, _ when t.Name == "float" => Lucene.Net.Search.SortField.FLOAT, _ when t.Name == "double" => Lucene.Net.Search.SortField.DOUBLE, _ when t.Name == "string" => Lucene.Net.Search.SortField.STRING, _ when t.Name == "byte" => Lucene.Net.Search.SortField.BYTE, _ when t.Name == "short" || t.Name == "Int16" => Lucene.Net.Search.SortField.SHORT, _ => -1 }; } public static void GetString<T>(this object t) { Console.WriteLine(typeof(T).Name); } }
4:特性
4.1(有具体实现)
//Lucene标注特性 [AttributeUsage(AttributeTargets.Property)] class LuceneDefineAttribute : Attribute { public LuceneDefineAttribute() { Store = Lucene.Net.Documents.Field.Store.YES; Index = Lucene.Net.Documents.Field.Index.ANALYZED; } public Lucene.Net.Documents.Field.Store Store { get; set; } public Lucene.Net.Documents.Field.Index Index { get; set; } } //排序特性 [System.AttributeUsage(System.AttributeTargets.Property)] internal class SpecidSortAttribute : System.Attribute { public SpecidSortAttribute() { Desc = true; Order = 0; } public bool Desc { get; set; } public int Order { get; set; } }
4.2(无具体实现,只是标注一下有便于反射时使用)
public class SpecidQueryAttribute : Attribute { } public class TermQueryAttribute : SpecidQueryAttribute { } public class WildcardQueryAttribute : SpecidQueryAttribute { } public class FuzzyQueryAttribute : SpecidQueryAttribute { } public class NumericRangeQueryAttribute : SpecidQueryAttribute { } public class PhraseQueryAttribute : SpecidQueryAttribute { } public class PrefixQueryAttribute : SpecidQueryAttribute { } class SpecidFilterAttribute:Attribute { }
使用:
public void Test<T>(T t) { CreateIndexWriter(@"C:\Users\FanLin\Desktop\index"); var list = new List<T>(); list.Add(t); CreateIndex(list); QueryByKeyWord<T>("搜索", false, null, 100, null, "NAME"); var query1 = CreateQuery<T,Lucene.Net.Search.TermQuery, Util.Attributes.TermQueryAttribute>("搜索"); var query = CreateBooleanQuery((query1, Lucene.Net.Search.Occur.SHOULD)); QueryBySpecidQuery(query); }
总结:对Lucene一个简单的封装,也让自己了解一下,虽然平时用不到。而且还有什么比抄代码更快乐的呢
本来想把DContext注入进去,使T通用,但是目前能力有限还没有找到好方法。就只能使用泛型了。
参考文档:
http://www.luofenming.com/show.aspx?id=ART2021110700001
https://blog.csdn.net/qq_21137441/article/details/98941178