Libation/Source/LibationSearchEngine/LuceneExtensions.cs
2023-06-13 09:05:17 -06:00

72 lines
3.2 KiB
C#

using System;
using System.Collections.Generic;
using DataLayer;
using Lucene.Net.Analysis;
using Lucene.Net.Documents;
using Lucene.Net.QueryParsers;
using Lucene.Net.Search;
namespace LibationSearchEngine
{
// field names are case specific and, due to StandardAnalyzer, content is case INspecific
internal static class LuceneExtensions
{
internal static void AddAnalyzed(this Document document, string name, string value)
{
if (value is not null)
document.Add(new Field(name.ToLowerInvariant(), value, Field.Store.YES, Field.Index.ANALYZED));
}
internal static void RemoveRule(this Document document, IndexRule rule)
{
// fields are key value pairs. MULTIPLE FIELDS CAN POTENTIALLY HAVE THE SAME KEY.
// ie: must remove old before adding new else will create unwanted duplicates.
foreach (var name in rule.FieldNames)
document.RemoveFields(name.ToLowerInvariant());
}
internal static void AddIndexRule(this Document document, IndexRule rule, LibraryBook libraryBook)
{
string value = rule.GetValue(libraryBook);
if (value is null) return;
foreach (var name in rule.FieldNames)
{
// fields are key value pairs and MULTIPLE FIELDS CAN HAVE THE SAME KEY.
// splitting authors and narrators and/or tags into multiple fields could be interesting research.
// it could allow for more advanced searches, or maybe it could break broad searches.
// all searching should be lowercase
// external callers have the reasonable expectation that product id will be returned CASE SPECIFIC
var field = rule.FieldType switch
{
FieldType.Bool => new Field(name.ToLowerInvariant(), value, Field.Store.YES, Field.Index.ANALYZED_NO_NORMS),
FieldType.String => new Field(name.ToLowerInvariant(), value, Field.Store.YES, Field.Index.ANALYZED),
FieldType.Number => new Field(name.ToLowerInvariant(), value, Field.Store.YES, Field.Index.NOT_ANALYZED),
FieldType.ID => new Field(name.ToLowerInvariant(), value, Field.Store.YES, Field.Index.NOT_ANALYZED),
FieldType.Raw => new Field(name, value, Field.Store.YES, Field.Index.NOT_ANALYZED),
_ => throw new KeyNotFoundException(),
};
document.Add(field);
}
}
internal static Query GetQuery(this Analyzer analyzer, string defaultField, string searchString)
=> new QueryParser(SearchEngine.Version, defaultField.ToLowerInvariant(), analyzer).Parse(searchString);
// put all numbers, including dates, into this format:
// ########.##
internal const int PAD_DIGITS = 8;
internal const string DECIMAL_PRECISION = ".00";
internal static string ToLuceneString(this int i) => ((double)i).ToLuceneString();
internal static string ToLuceneString(this float f) => ((double)f).ToLuceneString();
internal static string ToLuceneString(this DateTime dt)
=> dt.ToString("yyyyMMdd") + DECIMAL_PRECISION;
internal static string ToLuceneString(this DateTime? dt)
=> dt?.ToLuceneString() ?? "";
internal static string ToLuceneString(this double d)
=> d.ToString("0" + DECIMAL_PRECISION).PadLeft(PAD_DIGITS + DECIMAL_PRECISION.Length, '0');
}
}