Using SQLite, System.Data.SQLite and Dapper (in a Console Application; later Windows Service; high throughput); why "database is locked" is there anyway?
I even abstracted all calling to SQLite db in this method:
public static void LocalDbScope(Action<IDbConnection> action)
{
try
{
lock (DbLock)
{
using (var connection = Open(LocalStorageConnectionString))
{
action(connection);
}
}
}
catch (Exception xux)
{
ErrLog.Error(xux);
throw;
}
}
Turning on the memory-mapped option did not help either:
connection.Execute("PRAGMA wal_autocheckpoint=32; PRAGMA journal_size_limit = 2048;");
connection.Execute("PRAGMA mmap_size=" + GB);
And this is connection string:
var builder = new SQLiteConnectionStringBuilder
{
DataSource = storageDbFilePath,
FailIfMissing = false,
PageSize = 32 * KB,
CacheSize = 10 * MB,
ForeignKeys = false,
UseUTF16Encoding = false,
Pooling = true,
JournalMode = SQLiteJournalModeEnum.Wal,
SyncMode = SynchronizationModes.Normal,
DateTimeKind = DateTimeKind.Utc,
DateTimeFormat = SQLiteDateFormats.ISO8601,
DefaultIsolationLevel = IsolationLevel.ReadCommitted,
DefaultTimeout = (int)TimeSpan.FromMinutes(1).TotalMilliseconds
};
LocalStorageConnectionString = builder.ToString();
What am I missing here?
Note: When you google for "database is locked", all the top results (and whole first page) is about this problem in different programming languages and platforms. It seems there is something else about SQLite that I can not filter out of this picture.
As stated in my comment, I have NO idea what-so-ever, is going on without seeing more of your code.
Still, if you are not willing to change Dapper to Sqlite-net, below is a small non-blocking example, using your abstraction, which is not throwing any exceptions. Hope it helps you figure it out.
using System;
using System.Data;
using System.Data.SQLite;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Dapper;
namespace MyConsoleApplication
{
public class Program
{
static void Main(string[] args)
{
var test = new TestSQLite();
test.GoForIt();
}
}
public class Entity
{
public int Id { get; set; }
public string Content { get; set; }
}
public class TestSQLite
{
private const string ConnectionString = "Data Source=sqlitetest.sqlite";
private static readonly object DbLock = new object();
public void GoForIt()
{
CreateTable();
var random = new Random();
for (int i = 0; i < 100; i++)
{
if ( i % 2 != 0)
{
Task.Factory.StartNew(() => Thread.Sleep(random.Next(0, 200))).ContinueWith(other =>
LocalDbScope(action =>
{
var entity = new Entity {Content = "hoax"};
entity.Id = action.Query<int>(
#"insert into entity (content) values (#Content); select last_insert_rowid()",
entity).First();
var ids = action.Query<int>(#"select id from entity").ToList();
Console.WriteLine("Inserted id:{0}, all ids:[{1}]", entity.Id, string.Join(",", ids));
}));
}
else
{
Task.Factory.StartNew(() => Thread.Sleep(random.Next(200, 500))).ContinueWith(other =>
LocalDbScope(action =>
{
action.Execute(#"delete from entity");
Console.WriteLine("Deleted all entities");
}));
}
}
Console.ReadLine();
}
public static void LocalDbScope(Action<IDbConnection> action)
{
lock (DbLock)
{
using (var connection = new SQLiteConnection(ConnectionString))
action(connection);
}
}
private static void CreateTable()
{
using (IDbConnection c = new SQLiteConnection(ConnectionString))
{
c.Execute(#"drop table if exists entity");
c.Execute(#"create table entity (id integer primary key autoincrement, content varchar(100))");
}
}
}
}
Related
I am trying to display the items in my list via the console and I'm not sure how to achieve that.
Data is added to a list from a SQL server with the following code:
List:
namespace SSIS_FileWatcher
{
public class WikiList //custom list
{
public string Source { get; set; }
}
}
Code to add data to list:
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Text;
namespace SSIS_FileWatcher
{
public class getWikiData
{
public List<WikiList> Source()
{
using (SqlConnection connection = new SqlConnection(Helper.CnnVal("DEV-BRMSQL01")))
{
connection.Open();
SqlCommand sqlCommand = new SqlCommand("SELECT source FROM [REFERENCE].[KRI_METRIC_WIKI_AND_INGESTION_SCHEDULE] ", connection);
SqlDataReader reader = sqlCommand.ExecuteReader();
while (reader.Read())
{
List<WikiList> entries = new List<WikiList>();
while (reader.Read())
{
WikiList w = new WikiList();
w.Source = (string)reader["Source"];
//w.Metric_ID = (string)reader["Metric_ID"];
//w.name = (string)reader["name"];
entries.Add(w);
}
}
}
return List<WikiList>;
}
}
}
Main code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System.Data.SqlClient;
using System.Data;
namespace SSIS_FileWatcher
{
public class Worker : BackgroundService
{
public string path = #"\\p1l-nas-02\EntTechBURM_DATA\PRD\";
private readonly ILogger<Worker> _logger;
public Worker(ILogger<Worker> logger)
{
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
try
{
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
//add code to display list in console
await Task.Delay(60*1000, stoppingToken);
}
catch (Exception ex)
{
Console.WriteLine($"Exception: {ex.Message}");
}
}
}
}
}
As you can see in the last code sample, I commented where I would like to show the results from my list. If anyone can show me how to do this, it would be much appreciated.
first of all, set the return type of getWikiData to List<WikiList>().
(this you have done after an edit)
Then after calling getWikiData.Source(), you can create a string list like so:
var wikis = new getWikiData().Source();
string str = String.Join("\r\n", wikis.Select(x => x.Source));
Console.WriteLine(str);
If you want to add a bullet like structure, this can be achieved this way:
var wikis = new getWikiData().Source();
if (wikis.Count > 0)
{
string str = "\t- " + String.Join("\r\n\t- ", wikis.Select(x => x.Source));
Console.WriteLine(str);
}
edit after your comment
I modified your method to work, beware that you renamed the method:
public List<WikiList> Source()
{
List<WikiList> entries = new List<WikiList>();
using (SqlConnection connection = new SqlConnection(Helper.CnnVal("DEV-BRMSQL01")))
{
connection.Open();
SqlCommand sqlCommand = new SqlCommand("SELECT source FROM [REFERENCE].[KRI_METRIC_WIKI_AND_INGESTION_SCHEDULE] ", connection);
SqlDataReader reader = sqlCommand.ExecuteReader();
while (reader.Read())
{
while (reader.Read())
{
WikiList w = new WikiList();
w.Source = (string)reader["Source"];
//w.Metric_ID = (string)reader["Metric_ID"];
//w.name = (string)reader["name"];
entries.Add(w);
}
}
}
return entries;
}
You could use the JavaScriptSerializer class (add reference to System.Web.Extensions):
using System.Web.Script.Serialization;
after that
var wikis = getWikiData();
var json = new JavaScriptSerializer().Serialize(wikis);
Console.WriteLine(json);
Also, you can use Newtonsoft
ref- https://www.newtonsoft.com/json
you don' t need WikiData class
public List<string> Source()
{
List<string> entries = new List<string>();
using (SqlConnection connection = new SqlConnection(Helper.CnnVal("DEV-BRMSQL01")))
{
...
while (reader.Read()) entries.Add(reader["Source"].ToString());
reader.Close();
}
return entries;
}
and how to display
var getWikiData= new getWikiData();
var source =getWikiData.Source();
Console.WriteLine(string.Join(Join("\n\r",source));
To provide an alternative method (Cedric's will work, but if there's lots of data it may look like nothing's happening in the console for a while; so you may desire to print each line as it's retrieved):
If so, you could tweak the class definition to:
public class WikiList //custom list
{
public string Source { get; set; }
public void WriteToConsole()
{
Console.WriteLine(Source);
}
}
Allowing getWikiData to change to:
public class getWikiData
{
public List<WikiData> Entries {get;set;}
public getWikiData()
{
using (SqlConnection connection = new SqlConnection(Helper.CnnVal("DEV-BRMSQL01")))
{
connection.Open();
SqlCommand sqlCommand = new SqlCommand("SELECT source FROM [REFERENCE].[KRI_METRIC_WIKI_AND_INGESTION_SCHEDULE] ", connection);
SqlDataReader reader = sqlCommand.ExecuteReader();
while (reader.Read())
{
Entries = new List<WikiList>();
WikiList w = new WikiList();
w.Source = (string)reader["Source"];
//w.Metric_ID = (string)reader["Metric_ID"];
//w.name = (string)reader["name"];
Entries.Add(w);
w.WriteToConsole();
}
}
}
}
Meaning you just call getWikiData in your worker method:
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
try
{
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
getWikiData wikiData = new getWikiData();
await Task.Delay(60*1000, stoppingToken);
}
catch (Exception ex)
{
Console.WriteLine($"Exception: {ex.Message}");
}
}
}
I am currently undertaking a project in which I am trying to make a RPG for a discord bot. I am currently struggling with how to implement a way to keep data for different servers separate. For example, I'm trying to store the location of the party for each server. I have tried testing moving from 'town' to 'forest'. It works on the server that the command is used, but all other servers that the bot is on also have their location updated to 'forest'. Since I'm new to c# as well I am struggling to work out a way to keep the location being updated on each server.
A possible solution would be to store an object for each guild in an array and reference it whenever guild specific data is required, however this doesn't seem like an elegant solution.
What would be the best way to achieve data separation between guilds?
MAIN
using Discord;
using Discord.Commands;
using Discord.WebSocket;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using TestBot2.Modules;
namespace TestBot2
{
class Program
{
static void Main(string[] args){
new Program().RunBotAsync().GetAwaiter().GetResult();
}
private DiscordSocketClient _client;
private CommandService _command;
private IServiceProvider _service;
public async Task RunBotAsync()
{
_client = new DiscordSocketClient();
_command = new CommandService();
_service = new ServiceCollection()
.AddSingleton(_client)
.AddSingleton(_command)
.BuildServiceProvider();
string botToken = *** BOT TOKEN ***;
//event subscription
_client.Log += Log;
await RegisterCommandAsync();
await _client.LoginAsync(TokenType.Bot, botToken);
await _client.StartAsync();
await Task.Delay(-1);
}
private Task Log(LogMessage arg)
{
Console.WriteLine(arg);
return null;
}
public async Task RegisterCommandAsync()
{
_client.MessageReceived += HandleCommandAsync;
await _command.AddModulesAsync(Assembly.GetEntryAssembly());
}
private async Task HandleCommandAsync(SocketMessage arg)
{
var message = arg as SocketUserMessage;
if (!(message is SocketUserMessage) || message.Author.IsBot) {
return;
}
int argPos = 1;
if (message.HasStringPrefix("cf!", ref argPos) || message.HasMentionPrefix(_client.CurrentUser, ref argPos))
{
var context = new SocketCommandContext(_client, message);
var result = await _command.ExecuteAsync(context, argPos+1, _service);
if (!result.IsSuccess)
Console.WriteLine(result.ErrorReason);
}
}
}
}
UTILITY
static string location = "town"; //curent loc
static string[] locations = //array of vlaid loc
{
"town", "forest"
};
int[,] travelMtx = new int[,] //distance matrix
{
{0,2 },
{2,0 }
};
public string D6()
{
Random rnd = new Random();
string reply;
reply = Convert.ToString(rnd.Next(1, 7));
return reply;
}
public string charName(string charowner = "")
{
string charname;
System.Data.OleDb.OleDbConnection conn = new System.Data.OleDb.OleDbConnection();
conn.ConnectionString = [FILE LOCATION]
conn.Open();
String my_query = "SELECT CharName FROM Chars WHERE CharOwner='" + charowner + "'";
Console.WriteLine(my_query);
OleDbCommand cmd = new OleDbCommand(my_query, conn);
charname = (string)cmd.ExecuteScalar();
Console.Write(charname);
return charname;
}
public string usermention(string user = "")
{
return user;
}
public string getLoc()
{
return Utility.location;
}
public void setLoc(string location)
{
Utility.location = location;
}
public bool checkLoc(string dest)
{
for (int i = 0; i < locations.Length; i++)
{
if (dest.ToLower() == locations[i])
{
return true;
}
}
return false;
}
public int travelTime(string location, string dest)
{
int x = 0;
int y = 0;
for (int i = 0; i < locations.Length; i++)
{
if (location.ToLower() == locations[i])
{
x = i;
}
if (dest.ToLower() == locations[i])
{
y= i;
}
}
return travelMtx[x,y];
}
}
}
TRAVEL
public class Travel : ModuleBase<SocketCommandContext>
{
[Command("Travel")]
public async Task PingAsync(string dest = "")
{
Utility Util = new Utility();
string loc = Util.getLoc();
int travelTime = 0;
if (Util.checkLoc(dest) == true)
{
travelTime = Util.travelTime(loc, dest);
}
Util.setLoc(dest);
await ReplyAsync("you are now in " + dest + " it took " + travelTime + " days" );
}
}
}
I think you could try to store it together with the serverip, so that you can ask for CharOwner='" + charowner + "'" and ServerIp='" + serverip + "'" in you WHERE part of the sql.
It's just a guess, but maybe it works. :)
i am trying to create a DB with C# WinForm Application using SMO. i have created this class to manage things:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.SqlServer.Management.Smo;
using System.Collections.Specialized;
using Microsoft.SqlServer.Management.Common;
namespace WindowsFormsApp3
{
class SqlServerController
{
//ServerConnection connection = new ServerConnection("MSSQLSERVER", "sysAdmin", "");
private Server m_server=null;
public SqlServerController (string server)
{
m_server = new Server(server);
}
public void AttachDatabase (string database, StringCollection files,AttachOptions options)
{
m_server.AttachDatabase(database, files, options);
}
public void AddBackupDevice(string name)
{
BackupDevice device = new BackupDevice(m_server,name);
m_server.BackupDevices.Add(device);
}
public string GetServerVersion(string serverName)
{
return m_server.PingSqlServerVersion(serverName).ToString();
}
public int CountActiveConnections(string database)
{
return m_server.GetActiveDBConnectionCount(database);
}
public void DeleteDatabase (string database)
{
m_server.KillDatabase(database);
}
public void DetachDatabse (string database, bool updatestatistics,bool removeFullTextIndex)
{
m_server.DetachDatabase(database, updatestatistics, removeFullTextIndex);
}
public void CreateDatabse (string database)
{
Database db = new Database(m_server, database);
db.Create();
}
public void CreateTable(string database, string table, List<Column> ColumnList,List<Index> IndexList)
{
Database db = m_server.Databases[database];
Table newTable = new Table(db, table);
foreach (Column column in ColumnList)
newTable.Columns.Add(column);
if (IndexList !=null)
{
foreach (Index index in IndexList)
newTable.Indexes.Add(index);
}
newTable.Create();
}
public Column CreateColumn (string name, DataType type, string #default,bool isIdentity,bool nullable)
{
Column column = new Column();
column.DataType = type;
column.Default = #default;
column.Identity = isIdentity;
column.Nullable = nullable;
return column;
}
public Index CreateIndex(string name, bool isClustered, IndexKeyType type,string[] columnNameList)
{
Index index = new Index();
index.Name = name;
index.IndexKeyType = type;
index.IsClustered = isClustered;
foreach (string columnName in columnNameList)
index.IndexedColumns.Add(new IndexedColumn(index, columnName));
return index;
}
//public object ShowTable(string database,string table)
//{
// var allData = from
//}
}
}
also i have a simple button that creates DB, it runs the code belove on click event:
private void btnCreateDatabase_Click(object sender, EventArgs e)
{
SQL.CreateDatabse("BetaDB");
List<Column> ColumnList = new List<Column>();
ColumnList.Add(SQL.CreateColumn("id", DataType.Int,"" ,true, false));
ColumnList.Add(SQL.CreateColumn("name", DataType.NVarChar(50), "", false, false));
ColumnList.Add(SQL.CreateColumn("UID", DataType.NVarChar(200), "", false, false));
ColumnList.Add(SQL.CreateColumn("Pass", DataType.NVarChar(50), "", false, false));
SQL.CreateTable("BetaDB", "userha", ColumnList, null);
}
while creating the table i am getting an exception in Visual Studio
error message
the exception message tells me that there is an issue setting data type for column in this function::
public Column CreateColumn (string name, DataType type, string #default,bool isIdentity,bool nullable)
{
Column column = new Column();
column.DataType = type; // exception message
column.Default = #default;
column.Identity = isIdentity;
column.Nullable = nullable;
return column;
}
i had exactly the same problem, and i solved it by using constructor to create Column:
var newTable = new Table(srv.Databases["MyDatabase"], "MyTable");
var c = new Column(newTable, "MyColumn");
c.DataType = new DataType(SqlDataType.NVarCharMax);
newTable.Columns.Add(c);
newTable.Create();
Rookie here needing help. I'm trying to build a prototype with the neo4j .NET driver using Bolt. My aim with the prototype is building multiple methods for creation and searches in the db, but only one method to connect to the db - here I'm continuously having problems. I've Googled all weekend for examples, tutorials and traversed through the documentation and now I need your help.
Programs.cs
using System;
using DTUneo4jConsoleApp.Db;
namespace DTUneo4jConsoleApp
{
public class Program
{
public static void Main(string[] args)
{
MyProperties something = new MyProperties();
neo4jdb session = new neo4jdb();
session.Run($"CREATE (a:Person {{name:'{something.Name}', title:'{something.Title}'}})");
var result = session.Run($"MATCH (a:Person) WHERE a.name = '{something.Name}' RETURN a.name AS name, a.title AS title");
foreach (var record in result)
{
Console.WriteLine($"{record["title"].As<string>()} {record["name"].As<string>()}");
}
Console.ReadKey();
}
}
public class MyProperties
{
public string Name { get; set; }
public string Title { get; set; }
}
}
db.cs
using Neo4j.Driver.V1;
namespace DTUneo4jConsoleApp.Db
{
public class neo4jdb
{
public static void Connection()
{
using (var driver = GraphDatabase.Driver("bolt://localhost", AuthTokens.Basic("user", "pass")))
using (var session = driver.Session())
{
}
}
}
}
When I instantiate the neo4jdb session = new neo4jdb(); I don't get i.e. the Run() method from the driver.
I hope someone can guide me in the right direction.
I am doing it like this:
public static List<IStatementResult> ExecuteCypher(List<Statement> statements)
{
List<IStatementResult> results = new List<IStatementResult>();
using (var driver = GraphDatabase.Driver("bolt://localhost", AuthTokens.Basic("user", "pass")))
{
using (var session = driver.Session())
{
using (var tx = session.BeginTransaction())
{
foreach (var statement in statements)
{
results.Add(tx.Run(statement));
}
tx.Success();
}
}
}
return results;
}
usage:
MyProperties something = new MyProperties();
var createCypher = new Statement($"CREATE (a:Person {{name:'{something.Name}', title:'{something.Title}'}})");
var matchCypher = new Statement($"MATCH (a:Person) WHERE a.name = '{something.Name}' RETURN a.name AS name, a.title AS title");
var statements = new List<Statement>();
statements.Add(createCypher);
statements.Add(matchCypher);
var results = ExecuteCypher(statements);
//you can now query result for each statement or
//your query your desired result
foreach (var record in results.Last())
{
Console.WriteLine($"{record["title"].As<string>()} {record["name"].As<string>()}");
}
In this way I can also create multiple records in a single transaction and get the result of all those as well.
I'm trying to create a search function for my website using Elastic Search and NEST. You can see my code below and I get results if I search for complete (and almost comlete) words.
Ie, if I search for "Buttermilk" or "Buttermil" I get a hit on my document containing the word "Buttermilk".
However, what I try to accomplish is if I search for "Butter", I should have a result with all three documents which have words that starts with "Butter". I thought this was solved by using FuzzyLikeThis?
Can anyone see what I'm doing wrong and point me in the right direction?
I created a console-app and the complete code you can see here:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Nest;
using Newtonsoft.Json;
namespace ElasticSearchTest
{
class Program
{
static void Main(string[] args)
{
var indexSettings = new IndexSettings();
indexSettings.Analysis.Analyzers["text-en"] = new SnowballAnalyzer { Language = "English" };
ElasticClient.CreateIndex("elastictesting", indexSettings);
var testItem1 = new TestItem {
Id = 1,
Name = "Buttermilk"
};
ElasticClient.Index(testItem1, "elastictesting", "TestItem", testItem1.Id);
var testItem2 = new TestItem {
Id = 2,
Name = "Buttercream"
};
ElasticClient.Index(testItem2, "elastictesting", "TestItem", testItem2.Id);
var testItem3 = new TestItem {
Id = 3,
Name = "Butternut"
};
ElasticClient.Index(testItem3, "elastictesting", "TestItem", testItem3.Id);
Console.WriteLine("Write search phrase:");
var searchPhrase = Console.ReadLine();
var searchResults = Search(searchPhrase);
Console.WriteLine("Number of search results: " + searchResults.Count());
foreach (var item in searchResults) {
Console.WriteLine(item.Name);
}
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
private static List<TestItem> Search(string searchPhrase)
{
var query = BuildQuery(searchPhrase);
var result = ElasticClient
.Search(query)
.Documents
.Select(d => d)
.Distinct()
.ToList();
return result;
}
public static ElasticClient ElasticClient
{
get
{
var localhost = new Uri("http://localhost:9200");
var setting = new ConnectionSettings(localhost);
setting.SetDefaultIndex("elastictesting");
return new ElasticClient(setting);
}
}
private static SearchDescriptor<TestItem> BuildQuery(string searchPhrase)
{
var querifiedKeywords = string.Join(" AND ", searchPhrase.Split(' '));
var filters = new BaseFilter[1];
filters[0] = Filter<TestItem>.Bool(b => b.Should(m => m.Query(q =>
q.FuzzyLikeThis(flt =>
flt.OnFields(new[] {
"name"
}).LikeText(querifiedKeywords)
.PrefixLength(2)
.MaxQueryTerms(1)
.Boost(2))
)));
var searchDescriptor = new SearchDescriptor<TestItem>()
.Filter(f => f.Bool(b => b.Must(filters)))
.Index("elastictesting")
.Type("TestItem")
.Size(500);
var jsons = JsonConvert.SerializeObject(searchDescriptor, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
return searchDescriptor;
}
}
class TestItem {
public int Id { get; set; }
[ElasticProperty(Analyzer = "text-en", Index = FieldIndexOption.analyzed)]
public string Name { get; set; }
}
}
Edited 2014-04-01 11:18
Well, I ended up using MultiMatch and QueryString, so this it how my code looks now. Hope it mey help anyone in the furure. Also, I added a Description property to my TestItem to illustrate multimatch.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Nest;
using Newtonsoft.Json;
namespace ElasticSearchTest
{
class Program
{
static void Main(string[] args)
{
var indexSettings = new IndexSettings();
ElasticClient.CreateIndex("elastictesting", indexSettings);
var testItem1 = new TestItem {
Id = 1,
Name = "Buttermilk",
Description = "butter with milk"
};
ElasticClient.Index(testItem1, "elastictesting", "TestItem", testItem1.Id);
var testItem2 = new TestItem {
Id = 2,
Name = "Buttercream",
Description = "Butter with cream"
};
ElasticClient.Index(testItem2, "elastictesting", "TestItem", testItem2.Id);
var testItem3 = new TestItem {
Id = 3,
Name = "Butternut",
Description = "Butter with nut"
};
ElasticClient.Index(testItem3, "elastictesting", "TestItem", testItem3.Id);
Console.WriteLine("Write search phrase:");
var searchPhrase = Console.ReadLine();
var searchResults = Search(searchPhrase);
Console.WriteLine("Number of search results: " + searchResults.Count());
foreach (var item in searchResults) {
Console.WriteLine(item.Name);
Console.WriteLine(item.Description);
}
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
private static List<TestItem> Search(string searchPhrase)
{
var query = BuildQuery(searchPhrase);
var result = ElasticClient
.Search(query)
.Documents
.Select(d => d)
.Distinct()
.ToList();
return result;
}
public static ElasticClient ElasticClient
{
get
{
var localhost = new Uri("http://localhost:9200");
var setting = new ConnectionSettings(localhost);
setting.SetDefaultIndex("elastictesting");
return new ElasticClient(setting);
}
}
private static SearchDescriptor<TestItem> BuildQuery(string searchPhrase)
{
var searchDescriptor = new SearchDescriptor<TestItem>()
.Query(q => q
.MultiMatch(m =>
m.OnFields(new[] {
"name",
"description"
}).QueryString(searchPhrase).Type(TextQueryType.PHRASE_PREFIX)
)
)
.Index("elastictesting")
.Type("TestItem")
.Size(500);
var jsons = JsonConvert.SerializeObject(searchDescriptor, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
return searchDescriptor;
}
}
class TestItem {
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
}
Instead of using FuzzyLikequery.. use prefix query its more fast and accurate..!
for more information refer
curl -XPOST "http://localhost:9200/try/indextype/_search" -d'
{
"query": {
"prefix": {
"field": {
"value": "Butter"
}
}
}
}'
create above query in NEST and try again..!
This has nothing to do with FuzzyLikeThis.
You can use prefixquery as suggested by #BlackPOP out of the box.
You could also opt for using EdgeNGrams, this will tokenize your input on index-time. The result faster performance as compared to prefixquery, offset against increased index size.
One thing to keep in mind is that prefixquery only works on non-analyzed fields, so if you want to do any anaylzing at indexing-time, you're probably better off using EdgeNGrams.
Please read up on anaylzers etc, if you don't know what they are.
Some refs:
http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-analyzers.html
http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-edgengram-tokenizer.html
See How can I do a prefix search in ElasticSearch in addition to a generic query string? for a similar question.