Hello everyone,
I’m trying to sort a field with lowercase and with their full content in NHibernate-Search.
I downloaded the code from NHibernate-Search github directory, to update our codebase to latest NHibernate version to prevent vulnerabilities.
Anyway, I’m unable sort a text as lowercase and with full content. It was working before but I guess the tokenization changed and now sorting doesnt work like before.
Here is the code:
using System;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using FluentNHibernate.Mapping;
using NHibernate;
using System.Linq;
using NHibernate.Search;
using NHibernate.Search.Attributes;
using NHibernate.Search.Store;
using NHibernate.Search.Event;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Search;
using Lucene.Net.Analysis.Core;
using Lucene.Net.Analysis;
using Lucene.Net.Util;
using System.IO;
namespace MyNHibernate.LuceneSort
{
internal class BasicStringSort
{
static void Main()
{
Console.WriteLine("Testing NHibernate Sort");
Console.WriteLine($"NHibernate Version: {typeof(ISession).Assembly.GetName().Version}");
Account A1, A2, A3, A4, A5, A6;
var sessionFactory = CreateSessionFactory();
DeleteAccounts(sessionFactory);
var allAccounts = new Account[] { };
using (var session = sessionFactory.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
A1 = new Account("mgn");
A2 = new Account("MGN");
A3 = new Account("Third");
A4 = new Account("MGN");
A5 = new Account("qwewqewq");
A6 = new Account("EUROPE");
allAccounts = [A1, A2, A3, A4, A5, A6];
session.SaveOrUpdate(A1);
session.SaveOrUpdate(A2);
session.SaveOrUpdate(A3);
session.SaveOrUpdate(A4);
session.SaveOrUpdate(A5);
session.SaveOrUpdate(A6);
transaction.Commit();
}
}
using (var session = sessionFactory.OpenSession())
{
var fullTextSession = Search.CreateFullTextSession(session);
var fullTextQuery = fullTextSession.CreateFullTextQuery<Account>("*:*")
.SetSort(new Sort(new SortField("Name_sort", SortFieldType.STRING, false)));
var nhSearchResults = fullTextQuery.List<Account>();
foreach (var result in nhSearchResults)
{
Console.WriteLine($"Found Account: {result.Id}-{result.Name}");
}
var sortedAccounts = allAccounts.OrderBy(w => w.Name.ToLower()).ToArray();
if (sortedAccounts.Select(a => a.Name).SequenceEqual(nhSearchResults.Select(a => a.Name)))
{
Console.WriteLine("Sort worked properly.");
}
else
{
Console.WriteLine("Error! Sort didn't work properly!");
}
}
DeleteAccounts(sessionFactory);
}
private static void DeleteAccounts(ISessionFactory sessionFactory)
{
using var session = sessionFactory.OpenSession();
using var transaction = session.BeginTransaction();
session.CreateQuery("DELETE FROM Account").ExecuteUpdate();
transaction.Commit();
}
public static ISessionFactory CreateSessionFactory()
{
var factory = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2005
.ShowSql()
.ConnectionString("Data Source=.;Initial Catalog=test_db;User Id=id;Password=pw"))
.Mappings(m =>
m.FluentMappings
.Add<AccountMap>()
)
.ExposeConfiguration(cfg =>
{
cfg.SetProperty("hibernate.search.default.directory_provider", typeof(RAMDirectoryProvider).AssemblyQualifiedName);
cfg.SetProperty("hibernate.search.default.indexBase.create", "true");
cfg.SetProperty("hibernate.search.analyzer", typeof(StandardAnalyzer).AssemblyQualifiedName);
cfg.SetProperty("hibernate.search.indexing_strategy", "event");
cfg.SetListener(NHibernate.Event.ListenerType.PostUpdate, new FullTextIndexEventListener());
cfg.SetListener(NHibernate.Event.ListenerType.PostInsert, new FullTextIndexEventListener());
cfg.SetListener(NHibernate.Event.ListenerType.PostDelete, new FullTextIndexEventListener());
})
.BuildSessionFactory();
using (var session = factory.OpenSession())
{
var searchFactory = Search.CreateFullTextSession(session).SearchFactory;
searchFactory.Optimize();
}
return factory;
}
}
[Indexed]
public class Account
{
[DocumentId]
public virtual int Id { get; protected set; }
public virtual int LastDataVersion { get; set; }
[Field(Name = "Name_sort", Index = Index.UnTokenized)]
[Analyzer(typeof(LowerKeywordAnalyzer))]
public virtual string Name { get; set; }
public Account()
{
Name = string.Empty;
}
public Account(string name)
{
Name = name;
}
public override string ToString() => $"Name:{Name}";
}
public class AccountMap : ClassMap<Account>
{
public AccountMap()
{
Schema("accounts");
Table("Accounts");
Id(x => x.Id);
Map(x => x.LastDataVersion);
Map(x => x.Name, "Name");
}
}
public class LowerKeywordAnalyzer : Analyzer
{
protected override TokenStreamComponents CreateComponents(string fieldName, TextReader reader)
{
Tokenizer tokenizer = new KeywordTokenizer(reader);
TokenStream tokenStream = new LowerCaseFilter(LuceneVersion.LUCENE_48, tokenizer);
return new TokenStreamComponents(tokenizer, tokenStream);
}
}
}
I looked at the docs and I found that I need to use Normalizer, but I couldnt find the Normalizer in NHibernate: Hibernate Search 5.8.2.Final: Reference Guide
All I want is something works similar to this:
var sortedAccounts = allAccounts.OrderBy(w => w.Name.ToLower());