diff --git a/aspnet-core/.gitignore b/aspnet-core/.gitignore
index a6454ea49..ed4f124ad 100644
--- a/aspnet-core/.gitignore
+++ b/aspnet-core/.gitignore
@@ -3,4 +3,5 @@ LocalNuget
*.DotSettings.user
**/*.csproj.user
templates
-nupkg
\ No newline at end of file
+nupkg
+consoles
\ No newline at end of file
diff --git a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore.Elasticsearch/LINGYUN.Abp.WorkflowCore.Elasticsearch.csproj b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore.Elasticsearch/LINGYUN.Abp.WorkflowCore.Elasticsearch.csproj
new file mode 100644
index 000000000..21aa9a59f
--- /dev/null
+++ b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore.Elasticsearch/LINGYUN.Abp.WorkflowCore.Elasticsearch.csproj
@@ -0,0 +1,12 @@
+
+
+
+ netstandard2.0
+
+
+
+
+
+
+
+
diff --git a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore.Elasticsearch/LINGYUN/Abp/WorkflowCore/Elasticsearch/AbpElasticsearchIndexer.cs b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore.Elasticsearch/LINGYUN/Abp/WorkflowCore/Elasticsearch/AbpElasticsearchIndexer.cs
new file mode 100644
index 000000000..81122060e
--- /dev/null
+++ b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore.Elasticsearch/LINGYUN/Abp/WorkflowCore/Elasticsearch/AbpElasticsearchIndexer.cs
@@ -0,0 +1,140 @@
+using LINGYUN.Abp.Elasticsearch;
+using LINGYUN.Abp.WorkflowCore.Elasticsearch.Models;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using Nest;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Threading.Tasks;
+using WorkflowCore.Interface;
+using WorkflowCore.Models;
+using WorkflowCore.Models.Search;
+
+namespace LINGYUN.Abp.WorkflowCore.Elasticsearch
+{
+ public class AbpElasticsearchIndexer : ISearchIndex
+ {
+ private IElasticClient _client;
+
+ private readonly IElasticsearchClientFactory _elasticsearchClientFactory;
+ private readonly AbpWorkflowCoreElasticsearchOptions _options;
+ private readonly ILogger _logger;
+
+ public AbpElasticsearchIndexer(
+ ILogger logger,
+ IOptions options,
+ IElasticsearchClientFactory elasticsearchClientFactory)
+ {
+ _logger = logger;
+ _options = options.Value;
+ _elasticsearchClientFactory = elasticsearchClientFactory;
+ }
+
+ public async Task IndexWorkflow(WorkflowInstance workflow)
+ {
+ if (_client == null)
+ throw new InvalidOperationException("Not started");
+
+ var denormModel = WorkflowSearchModel.FromWorkflowInstance(workflow);
+
+ var result = await _client.IndexAsync(
+ denormModel,
+ idx => idx.Index(_options.IndexFormat));
+
+ if (!result.ApiCall.Success)
+ {
+ _logger.LogError(default(EventId), result.ApiCall.OriginalException, $"Failed to index workflow {workflow.Id}");
+ throw new ApplicationException($"Failed to index workflow {workflow.Id}", result.ApiCall.OriginalException);
+ }
+ }
+
+ public async Task> Search(string terms, int skip, int take, params SearchFilter[] filters)
+ {
+ if (_client == null)
+ throw new InvalidOperationException("Not started");
+
+ var result = await _client.SearchAsync(s => s
+ .Index(_options.IndexFormat)
+ .Skip(skip)
+ .Take(take)
+ .MinScore(!string.IsNullOrEmpty(terms) ? 0.1 : 0)
+ .Query(query => query
+ .Bool(b => b
+ .Filter(BuildFilterQuery(filters))
+ .Should(
+ should => should.Match(t => t.Field(f => f.Reference).Query(terms).Boost(1.2)),
+ should => should.Match(t => t.Field(f => f.DataTokens).Query(terms).Boost(1.1)),
+ should => should.Match(t => t.Field(f => f.WorkflowDefinitionId).Query(terms).Boost(0.9)),
+ should => should.Match(t => t.Field(f => f.Status).Query(terms).Boost(0.9)),
+ should => should.Match(t => t.Field(f => f.Description).Query(terms))
+ )
+ )
+ )
+ );
+
+ return new Page
+ {
+ Total = result.Total,
+ Data = result.Hits.Select(x => x.Source).Select(x => x.ToSearchResult()).ToList()
+ };
+ }
+
+ public async Task Start()
+ {
+ _client = _elasticsearchClientFactory.Create();
+ var nodeInfo = await _client.Nodes.InfoAsync();
+ if (nodeInfo.Nodes.Values.Any(x => Convert.ToUInt32(x.Version.Split('.')[0]) < 6))
+ throw new NotSupportedException("Elasticsearch verison 6 or greater is required");
+
+ var exists = await _client.Indices.ExistsAsync(_options.IndexFormat);
+ if (!exists.Exists)
+ {
+ await _client.Indices.CreateAsync(_options.IndexFormat);
+ }
+ }
+
+ public Task Stop()
+ {
+ return Task.CompletedTask;
+ }
+
+ private List, QueryContainer>> BuildFilterQuery(SearchFilter[] filters)
+ {
+ var result = new List, QueryContainer>>();
+
+ foreach (var filter in filters)
+ {
+ var field = new Field(filter.Property);
+ if (filter.IsData)
+ {
+ Expression> dataExpr = x => x.Data[filter.DataType.FullName];
+ var fieldExpr = Expression.Convert(filter.Property, typeof(Func