C# 使用apachelucene进行搜索
我一直在尝试实现Lucene,以加快我网站上的搜索速度 我的代码目前可以工作,但是,我认为我没有正确地使用Lucene。现在,我的搜索查询是C# 使用apachelucene进行搜索,c#,asp.net-mvc,lucene,C#,Asp.net Mvc,Lucene,我一直在尝试实现Lucene,以加快我网站上的搜索速度 我的代码目前可以工作,但是,我认为我没有正确地使用Lucene。现在,我的搜索查询是productName:asterisk(input)asterisk——我无法想象这是查找productName包含input的所有产品所应该做的。我认为这与我将字段保存到文档的方式有关 我的代码: LuceneHelper.cs using System; using System.Collections; using System.Collection
productName:asterisk(input)asterisk
——我无法想象这是查找productName
包含input
的所有产品所应该做的。我认为这与我将字段保存到文档的方式有关
我的代码:
LuceneHelper.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.Entity.Migrations.Model;
using System.Linq;
using System.Threading.Tasks;
using Lucene.Net;
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 Lucene.Net.Store;
using Rentpro.Models;
using RentPro.Models.Tables;
using RentProModels.Models;
namespace RentPro.Helpers
{
public class LuceneHelper
{
private const Lucene.Net.Util.Version Version = Lucene.Net.Util.Version.LUCENE_30;
private bool IndicesInitialized;
private List<Language> Languages = new List<Language>();
public void BuildIndices(DB db)
{
Languages = GetLanguages(db);
Analyzer analyzer = new StandardAnalyzer(Version);
List<Product> allProducts = db.GetAllProducts(true, false);
foreach (Language l in Languages)
{
BuildIndicesForLanguage(allProducts, analyzer, l.ID);
}
IndicesInitialized = true;
}
private void BuildIndicesForLanguage(List<Product> products, Analyzer analyzer, int id = 0)
{
using (
IndexWriter indexWriter = new IndexWriter(GetDirectory(id), analyzer,
IndexWriter.MaxFieldLength.UNLIMITED))
{
var x = products.Count;
foreach (Product p in products)
{
SearchProduct product = SearchProduct.FromProduct(p, id);
Document document = new Document();
Field productIdField = new Field("productId", product.ID.ToString(), Field.Store.YES, Field.Index.NO);
Field productTitleField = new Field("productName", product.Name, Field.Store.YES, Field.Index.ANALYZED);
Field productDescriptionField = new Field("productDescription", product.Description, Field.Store.YES, Field.Index.ANALYZED);
Field productCategoryField = new Field("productCategory", product.Category, Field.Store.YES, Field.Index.ANALYZED);
Field productCategorySynonymField = new Field("productCategorySynonym", product.CategorySynonym, Field.Store.YES, Field.Index.ANALYZED);
Field productImageUrlField = new Field("productImageUrl", product.ImageUrl, Field.Store.YES, Field.Index.NO);
Field productTypeField = new Field("productType", product.Type, Field.Store.YES, Field.Index.NO);
Field productDescriptionShortField = new Field("productDescriptionShort", product.DescriptionShort, Field.Store.YES, Field.Index.NO);
Field productPriceField = new Field("productPrice", product.Price, Field.Store.YES, Field.Index.NO);
document.Add(productIdField);
document.Add(productTitleField);
document.Add(productDescriptionField);
document.Add(productCategoryField);
document.Add(productCategorySynonymField);
document.Add(productImageUrlField);
document.Add(productTypeField);
document.Add(productDescriptionShortField);
document.Add(productPriceField);
indexWriter.AddDocument(document);
}
indexWriter.Optimize();
indexWriter.Commit();
}
}
public List<SearchProduct> Search(string input)
{
if (!IndicesInitialized)
{
BuildIndices(new DB());
return Search(input);
}
IndexReader reader = IndexReader.Open(GetCurrentDirectory(), true);
Searcher searcher = new IndexSearcher(reader);
Analyzer analyzer = new StandardAnalyzer(Version);
TopScoreDocCollector collector = TopScoreDocCollector.Create(100, true);
MultiFieldQueryParser parser = new MultiFieldQueryParser(Version,
new[] { "productDescription", "productCategory", "productCategorySynonym", "productName" }, analyzer)
{
AllowLeadingWildcard = true
};
searcher.Search(parser.Parse("*" + input + "*"), collector);
ScoreDoc[] hits = collector.TopDocs().ScoreDocs;
List<int> productIds = new List<int>();
List<SearchProduct> results = new List<SearchProduct>();
foreach (ScoreDoc scoreDoc in hits)
{
Document document = searcher.Doc(scoreDoc.Doc);
int productId = int.Parse(document.Get("productId"));
if (!productIds.Contains(productId))
{
productIds.Add(productId);
SearchProduct result = new SearchProduct
{
ID = productId,
Description = document.Get("productDescription"),
Name = document.Get("productName"),
Category = document.Get("productCategory"),
CategorySynonym = document.Get("productCategorySynonym"),
ImageUrl = document.Get("productImageUrl"),
Type = document.Get("productType"),
DescriptionShort = document.Get("productDescriptionShort"),
Price = document.Get("productPrice")
};
results.Add(result);
}
}
reader.Dispose();
searcher.Dispose();
analyzer.Dispose();
return results;
}
private string GetDirectoryPath(int languageId = 1)
{
return GetDirectoryPath(Languages.SingleOrDefault(x => x.ID == languageId).UriPart);
}
private string GetDirectoryPath(string languageUri)
{
return AppDomain.CurrentDomain.BaseDirectory + @"\App_Data\LuceneIndices\" + languageUri;
}
private List<Language> GetLanguages(DB db)
{
return db.Languages.ToList();
}
private int GetCurrentLanguageId()
{
return Translator.GetCurrentLanguageID();
}
private FSDirectory GetCurrentDirectory()
{
return FSDirectory.Open(GetDirectoryPath(GetCurrentLanguageId()));
}
private FSDirectory GetDirectory(int languageId)
{
return FSDirectory.Open(GetDirectoryPath(languageId));
}
}
public class SearchProduct
{
public int ID { get; set; }
public string Description { get; set; }
public string Name { get; set; }
public string ImageUrl { get; set; }
public string Type { get; set; }
public string DescriptionShort { get; set; }
public string Price { get; set; }
public string Category { get; set; }
public string CategorySynonym { get; set; }
public static SearchProduct FromProduct(Product p, int languageId)
{
return new SearchProduct()
{
ID = p.ID,
Description = p.GetText(languageId, ProductLanguageType.Description),
Name = p.GetText(languageId),
ImageUrl =
p.Images.Count > 0
? "/Company/" + Settings.Get("FolderName") + "/Pictures/Products/100x100/" +
p.Images.Single(x => x.Type == "Main").Url
: "",
Type = p is HuurProduct ? "HuurProduct" : "KoopProduct",
DescriptionShort = p.GetText(languageId, ProductLanguageType.DescriptionShort),
Price = p is HuurProduct ? ((HuurProduct)p).CalculatedPrice(1, !Settings.GetBool("BTWExLeading")).ToString("0.00") : "",
Category = p.Category.Name,
CategorySynonym = p.Category.Synonym
};
}
}
}
使用系统;
使用系统集合;
使用System.Collections.Generic;
使用System.Data.Entity.Migrations.Model;
使用System.Linq;
使用System.Threading.Tasks;
使用Lucene.Net;
使用Lucene.Net.Analysis;
使用Lucene.Net.Analysis.Standard;
使用Lucene.Net.Documents;
使用Lucene.Net.Index;
使用Lucene.Net.queryparser;
使用Lucene.Net.Search;
使用Lucene.Net.Store;
使用Rentpro.模型;
使用RentPro.Models.Tables;
使用RentProModels.Models;
命名空间RentPro.Helpers
{
公共类LuceneHelper
{
private const Lucene.Net.Util.Version=Lucene.Net.Util.Version.Lucene_30;
私有布尔指标初始化;
私有列表语言=新列表();
公共建筑索引(DB)
{
语言=GetLanguages(db);
分析仪=新标准分析仪(版本);
List allProducts=db.GetAllProducts(true,false);
foreach(语言中的语言l)
{
语言的构建标识(所有产品、分析仪、l.ID);
}
指示初始=真;
}
私有void buildIndicatesForLanguage(列出产品,Analyzer Analyzer,int id=0)
{
使用(
IndexWriter IndexWriter=新的IndexWriter(GetDirectory(id),analyzer,
IndexWriter.MaxFieldLength.UNLIMITED)
{
var x=产品计数;
foreach(产品中的产品p)
{
SearchProduct产品=SearchProduct.FromProduct(p,id);
文档=新文档();
Field productIdField=新字段(“productId”,product.ID.ToString(),Field.Store.YES,Field.Index.NO);
Field productTitleField=新字段(“productName”,product.Name,Field.Store.YES,Field.Index.analysis);
Field productDescriptionField=新字段(“productDescription”,product.Description,Field.Store.YES,Field.Index.Analysis);
Field productCategoryField=新字段(“productCategory”,product.Category,Field.Store.YES,Field.Index.Analysis);
Field productCategorySynonymField=新字段(“productCategorySynonym”,product.CategorySynonym,Field.Store.YES,Field.Index.ANALYZED);
Field productImageUrlField=新字段(“productImageUrl”,product.ImageUrl,Field.Store.YES,Field.Index.NO);
Field productTypeField=新字段(“productType”,product.Type,Field.Store.YES,Field.Index.NO);
Field productDescriptionShortField=新字段(“productDescriptionShort”,product.DescriptionShort,Field.Store.YES,Field.Index.NO);
Field productPriceField=新字段(“productPrice”,product.Price,Field.Store.YES,Field.Index.NO);
文件。添加(productIdField);
文件。添加(productTitleField);
文档.添加(productDescriptionField);
文件。添加(productCategoryField);
document.Add(productCategorySynonymField);
document.Add(productImageUrlField);
document.Add(productTypeField);
document.Add(productDescriptionShortField);
document.Add(productPriceField);
indexWriter.AddDocument(文档);
}
index writer.Optimize();
indexWriter.Commit();
}
}
公共列表搜索(字符串输入)
{
如果(!表示初始化)
{
构建索引(新数据库());
返回搜索(输入);
}
IndexReader=IndexReader.Open(GetCurrentDirectory(),true);
Searcher Searcher=新索引搜索器(读卡器);
分析仪=新标准分析仪(版本);
TopScoreDocCollector=TopScoreDocCollector.Create(100,true);
MultiFieldQueryParser解析器=新的MultiFieldQueryParser(版本,
新[]{“productDescription”、“productCategory”、“productCategorySynonym”、“productName”},analyzer)
{
AllowReadingWildcard=true
};
searcher.Search(parser.Parse(“*”+input+“*”),收集器);
ScoreDoc[]hits=collector.TopDocs().ScoreDocs;
List productIds=新列表();
列表结果=新列表();
foreach(点击中的ScoreDoc ScoreDoc)
{
Document Document=searcher.Doc(scoreDoc.Doc);
int productId=int.Parse(document.Get(“productId”);
如果(!productId.Contains(productId))
{
productId.Add(productId);
SearchProduct结果=新的SearchProduct
{
ID=productId,
Description=document.Get(“productDescription”),
Name=document.Get(“productName”),
类别=document.Get(“productCategory”),
CategorySynonym=document.Get(“productCategorySynonym”),
ImageUrl=document.Get(“productImageUrl”),
Type=document.Get(“productType”),
DescriptionShort=document.Get(“productDescriptionShort”),
价格=文件
public ActionResult Lucene(string SearchString, string SearchOrderBy, int? page, int? amount)
{
List<SearchProduct> searchResults = new List<SearchProduct>();
if (!SearchString.IsNullOrWhiteSpace())
{
LuceneHelper lucene = new LuceneHelper();
searchResults = lucene.Search(SearchString);
}
return View(new LuceneSearchResultsVM(db, SearchString, searchResults, SearchOrderBy, page ?? 1, amount ?? 10));
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic;
using System.Web;
using RentPro.Models.Tables;
using System.Linq.Expressions;
using System.Reflection;
using Microsoft.Ajax.Utilities;
using Rentpro.Models;
using RentPro.Helpers;
using RentProModels.Models;
namespace RentPro.ViewModels
{
public class LuceneSearchResultsVM
{
public List<SearchProduct> SearchProducts { get; set; }
public bool BTWActive { get; set; }
public bool BTWEXInput { get; set; }
public bool BTWShow { get; set; }
public bool BTWExLeading { get; set; }
public string FolderName { get; set; }
public string CurrentSearchString { get; set; }
public string SearchOrderBy { get; set; }
public int Page;
public int Amount;
public String SearchQueryString {
get
{
return Translator.Translate("Zoekresultaten voor") + ": " + CurrentSearchString + " (" +
SearchProducts.Count + " " + Translator.Translate("resultaten") + " - " +
Translator.Translate("pagina") + " " + Page + " " + Translator.Translate("van") + " " +
CalculateAmountOfPages() + ")";
}
set { }
}
public LuceneSearchResultsVM(DB db, string queryString, List<SearchProduct> results, string searchOrderBy, int page, int amt)
{
BTWActive = Settings.GetBool("BTWActive");
BTWEXInput = Settings.GetBool("BTWEXInput");
BTWShow = Settings.GetBool("BTWShow");
BTWExLeading = Settings.GetBool("BTWExLeading");
FolderName = Settings.Get("FolderName");
SearchProducts = results;
CurrentSearchString = queryString;
if (searchOrderBy.IsNullOrWhiteSpace())
{
searchOrderBy = "Name";
}
SearchOrderBy = searchOrderBy;
Amount = amt == 0 ? 10 : amt;
int maxPages = CalculateAmountOfPages();
Page = page > maxPages ? maxPages : page;
SearchLog.MakeEntry(queryString, SearchProducts.Count(), db, HttpContext.Current.Request.UserHostAddress);
}
public List<SearchProduct> GetOrderedList()
{
List<SearchProduct> copySearchProductList = new List<SearchProduct>(SearchProducts);
copySearchProductList = copySearchProductList.Skip((Page - 1) * Amount).Take(Amount).ToList();
switch (SearchOrderBy)
{
case "Price":
copySearchProductList.Sort(new PriceSorter());
break;
case "DateCreated":
return copySearchProductList; //TODO
default:
return copySearchProductList.OrderBy(n => n.Name).ToList();
}
return copySearchProductList;
}
public int CalculateAmountOfPages()
{
int items = SearchProducts.Count;
return items / Amount + (items % Amount > 0 ? 1 : 0);
}
}
public class PriceSorter : IComparer<SearchProduct>
{
public int Compare(SearchProduct x, SearchProduct y)
{
if (x == null || x.Price == "") return 1;
if (y == null || y.Price == "") return -1;
decimal priceX = decimal.Parse(x.Price);
decimal priceY = decimal.Parse(y.Price);
return priceX > priceY ? 1 : priceX == priceY ? 0 : -1;
}
}
}
test
est
st
t
for(int i = 0; i < product.SafeName.length()-1; i++){
Field productTitleSearchField = new Field("productNameSearch", product.SafeName.substring(i, product.SafeName.length()), Field.Store.NO, Field.Index.ANALYZED);
}
te
tes
es
est
st
IndexReader reader = IndexReader.Open(GetCurrentDirectory(), true);
Searcher searcher = new IndexSearcher(reader);
Analyzer analyzer = new StandardAnalyzer(Version);
//...
reader.Dispose();
searcher.Dispose();
analyzer.Dispose();
using (IndexReader reader = IndexReader.Open(GetCurrentDirectory(), true))
using (Searcher searcher = new IndexSearcher(reader))
using (Analyzer analyzer = new StandardAnalyzer(Version))
{
//Do whatever else here.. No need to call "dispose".
}
using (whatever foo = new whatever(), whatever bar = new whatever(), ...)
{
//do whatever here..
}