- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我一直在尝试实现 Lucene 来加快我网站上的搜索速度。
我的代码目前可以运行,但是,我认为我没有正确使用 Lucene。现在,我的搜索查询是 productName:asterisk(input)asterisk
- 我无法想象这是你应该做的来找到 productName
包含的所有产品输入
。我认为这与我将字段保存到文档的方式有关。
我的代码:
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
};
}
}
}
我如何调用 LuceneHelper:
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));
}
LuceneSearchResultsVM:
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;
}
}
}
如有任何帮助,我们将不胜感激。
查询:从产品中选择 Product.ID、Product.Description、Product.Name
等效于 SQL Server 查询:SELECT Product.ID、Product.Description、Product.Name FROM Product WHERE Product.Name LIKE '%Zelf%' OR Product.Description LIKE '%Zelf%'
基本上,Zelf
是输入。我想找到包含输入字符串的产品描述或产品名称的所有匹配项。
最佳答案
ucene not allows使用?或 * 作为搜索词的起始符号。为了克服这个问题,您需要在索引中存储从单词的任何位置到结束位置的子字符串。例如。对于单词测试,你应该放在索引中
test
est
st
t
我建议为此使用单独的字段。 Java 示例,如果您有一个短字段,其中包含一个单词,例如产品名称。
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);
}
在此之后,您可以使用以下查询字符串productNameSearch:(input)asterisk
或使用 PrefixQuery用于搜索包含 input
的产品名称。
如果您的字段中有多个单词,并且输入的长度足够合理,那么最好为该字段添加 NGramTokenFilter .如果您的输入字符串有从 n 到 m 的限制,您应该创建一个具有 n minGram 和 m maxGramm 的 NGram token 过滤器。如果你有单词 test
并且你将 2 到 3 个限制在你的索引词中
te
tes
es
est
st
之后你可以通过字符串搜索
ngrammField:(输入)
关于c# - 使用 Apache Lucene 进行搜索,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33825369/
我在我的应用程序中使用 Hibernate Search。其中一个子集合被映射为 IndexedEmbedded。子对象有两个字段,一个是 id,另一个是日期(使用日期分辨率到毫秒)。当我搜索 id=
The App Engine Search API有一个 GeoPoint 字段。可以用它来进行半径搜索吗?例如,给定一个 GeoPoint,查找位于特定半径内的所有文档。 截至目前,它看起来像 Ge
客户对我正在做的员工管理项目提出了这个新要求,以允许他们的用户进行自定义 bool 搜索。 基本上允许他们使用:AND、OR、NOT、括号和引号。 实现它的最佳方法是什么?我检查了 mysql,它们使
很想知道哪个更快 - 如果我有一个包含 25000 个键值对的数组和一个包含相同信息的 MySQL 数据库,搜索哪个会更快? 非常感谢大家! 最佳答案 回答这个问题的最好方法是执行基准测试。 关于ph
我喜欢 smartcase,也喜欢 * 和 # 搜索命令。但我更希望 * 和 # 搜索命令区分大小写,而/和 ?搜索命令遵循 smartcase 启发式。 是否有隐藏在某个地方我还没有找到的设置?我宁
我有以下 Marklogic 查询,当在查询控制台中运行时,它允许我检索具有管理员权限的系统用户: xquery version "1.0-ml"; import schema namespace b
我希望当您搜索例如“A”时,所有以“A”开头的全名都会出现。因此,如果名为“Andreas blabla”的用户将显示 我现在有这个: $query = "SELECT full_name, id,
我想在我的网站上添加对人名的搜索。好友列表已经显示在页面上。 我喜欢 Facebook 这样做的方式,您开始输入姓名,Facebook 只会显示与查询匹配的好友。 http://cl.ly/2t2V0
您好,我在我的网站上进行搜索时遇到此错误。 Fatal error: Uncaught Error: Call to undefined function mysql_connect() in /ho
声明( 叠甲 ):鄙人水平有限,本文为作者的学习总结,仅供参考。 1. 搜索介绍 搜索算法包括深度优先搜索(DFS)和广度优先搜索(BFS)这两种,从起点开始,逐渐扩大
我正在为用户列表使用 FuturBuilder。我通过 futur: fetchpost() 通过 API 获取用户。在专栏的开头,我实现了一个搜索栏。那么我该如何实现我的搜索栏正在搜索呢? Cont
我正在使用 MVC5,我想搜索结果并停留在同一页面,这是我在 Controller (LiaisonsProjetsPPController) 中执行搜索操作的方法: public ActionRes
Azure 搜索中的两种方法 Upload 与 MergeOrUpload 之间有什么区别。 他们都做完全相同的事情。即,如果文档不存在,它们都会上传文档;如果文档已经存在,则替换该文档。 由于这两种
实际上,声音匹配/搜索的当前状态是什么?我目前正在远程参与规划一个 Web 应用程序,该应用程序将包含和公开记录的短音频剪辑(最多 3-5 秒,人名)的数据库。已经提出了一个问题,是否可以实现基于用户
在商业应用程序中,具有数百个面并不罕见。当然,并非所有产品都带有所有这些标记。 但是在搜索时,我需要添加一个方面查询字符串参数,其中列出了我想要返回的所有方面。由于我事先不知道相关列表,因此我必须在查
当我使用nvcc 5.0编译.cu文件时,编译器会为我提供以下信息。 /usr/bin/ld: skipping incompatible /usr/local/cuda-5.0/lib/libcud
我正在使用基于丰富的 Lucene 查询解析器语法的 Azure 搜索。我将“~1”定义为距离符号的附加参数)。但我面临的问题是,即使存在完全匹配,实体也没有排序。 (例如,“blue~1”将返回“b
我目前有 3 个类,一个包含 GUI 的主类,我在其中调用此方法,一个包含数据的客户类,以及一个从客户类收集数据并将其放入数组列表的 customerList 类,以及还包含搜索数组列表方法。 我正在
假设我有多个 6 字符的字母数字字符串。 abc123、abc231、abc456、cba123、bac231 和 bac123 。 基本上我想要一个可以搜索和列出所有 abc 实例的选择语句。 我只
我有这个表 "Table"内容: +--------+ | Serial | +--------+ | d100m | <- expected result | D100M | <- expect
我是一名优秀的程序员,十分优秀!