Ejemplo n.º 1
0
        [HttpGet("import")] // todo this endpoint is test only...
        public async Task <IActionResult> Import()
        {
            var products = await _productsService.GetProducts();

            var productsToUpdate = products.Where(x => x.IsActive && !x.IsDeleted)
                                   .Select(x => new ProductSearchModel(x)).ToList();
            var productsToDelete = products.Where(x => !x.IsActive || x.IsDeleted)
                                   .Select(x => new ProductSearchModel(x)).ToList();

            if (productsToUpdate.Any())
            {
                var updateResponse = await _client.IndexManyAsync(productsToUpdate, IndexName.From <ProductSearchModel>());

                if (updateResponse.OriginalException != null)
                {
                    throw updateResponse.OriginalException;
                }
            }

            if (productsToDelete.Any())
            {
                var deleteResponse = await _client.DeleteManyAsync(productsToDelete, IndexName.From <ProductSearchModel>());

                if (deleteResponse.OriginalException != null)
                {
                    throw deleteResponse.OriginalException;
                }
            }

            return(Accepted());
        }
Ejemplo n.º 2
0
        public async Task Consume(ConsumeContext <Batch <ProductUpdatedEvent> > context)
        {
            var productsWithoutDuplicates = context.Message.GroupBy(x => x.Message.ProductDetails.Id)
                                            .Select(x => x.OrderByDescending(y => y.Message.UpdateDateUtc).FirstOrDefault())
                                            .ToList();

            var productsToUpdate = productsWithoutDuplicates.Where(x => x.Message.ProductDetails.IsActive && !x.Message.ProductDetails.IsDeleted)
                                   .Select(x => new ProductSearchModel(x.Message.ProductDetails)).ToList();
            var productsToDelete = productsWithoutDuplicates.Where(x => !x.Message.ProductDetails.IsActive || x.Message.ProductDetails.IsDeleted)
                                   .Select(x => new ProductSearchModel(x.Message.ProductDetails)).ToList();

            if (productsToUpdate.Any())
            {
                var updateResponse = await _client.IndexManyAsync(productsToUpdate, IndexName.From <ProductSearchModel>());

                if (updateResponse.OriginalException != null)
                {
                    throw updateResponse.OriginalException;
                }
            }

            if (productsToDelete.Any())
            {
                var deleteResponse = await _client.DeleteManyAsync(productsToDelete, IndexName.From <ProductSearchModel>());

                if (deleteResponse.OriginalException != null)
                {
                    throw deleteResponse.OriginalException;
                }
            }
        }
Ejemplo n.º 3
0
        /** === An example with requests */
        [U] public void UsingWithRequests()
        {
            /* Given the following CLR type that describes a document */
            var project = new Project {
                Name = "hello-world"
            };

            /** we can see an example of how `DocumentPath` helps your describe your requests more tersely */
            var request = new IndexRequest <Project>(2)
            {
                Document = project
            };

            request = new IndexRequest <Project>(project)
            {
            };

            /** when comparing with the full blown constructor and passing document manually,
             * `DocumentPath<T>`'s benefits become apparent.
             */
            request = new IndexRequest <Project>(IndexName.From <Project>(), TypeName.From <Project>(), 2)
            {
                Document = project
            };
        }
        public SampleElasticsearchClient(string endPoint, Amazon.RegionEndpoint regionEndPoint)
        {
            AWSCredentials    awsCredentials = FallbackCredentialsFactory.GetCredentials();
            AwsHttpConnection conn           = new AwsHttpConnection(regionEndPoint.SystemName,
                                                                     new StaticCredentialsProvider(new AwsCredentials()
            {
                AccessKey = awsCredentials.GetCredentials().AccessKey,
                SecretKey = awsCredentials.GetCredentials().SecretKey,
                Token     = awsCredentials.GetCredentials().Token
            }));

            var pool = new SingleNodeConnectionPool(new Uri(endPoint));
            ConnectionSettings settings = new ConnectionSettings(pool, conn)
                                          .DisableDirectStreaming()
                                          .InferMappingFor <LogEntry>(m => m.IndexName("logs"));

            //.DefaultMappingFor<LogEntry>(m => m.IndexName("logs"));

            _esClient = new ElasticClient(settings);

            IndexName logIndex = IndexName.From <LogEntry>();

            var req = new IndexExistsRequest(logIndex);
            var res = _esClient.IndexExists(req);

            if (!res.Exists)
            {
                _esClient.CreateIndex("logs", c => c
                                      .Mappings(md => md.Map <LogEntry>(m => m.AutoMap())));
            }
        }
Ejemplo n.º 5
0
        internal static IndexDescriptor <T> GetIndex <T>(this ElasticClient client) where T : EsDocument
        {
            //var col = client.GetIndicesPointingToAlias(aliasName);
            var indexDesc = new IndexDescriptor <T>(IndexName.From <T>());

            return(indexDesc);
        }
Ejemplo n.º 6
0
 public async Task Consume(ConsumeContext <PhotoRemovedEvent> context)
 {
     await _client.DeleteAsync(new DeleteRequest(IndexName.From <PhotoSearchModel>(), TypeName.From <PhotoSearchModel>(), Id.From(new PhotoSearchModel()
     {
         OriginalUrl = context.Message.OriginalUrl,
         PhotoId = context.Message.PhotoId,
         ProductId = context.Message.ProductId
     })));
 }
Ejemplo n.º 7
0
        public async Task FillElastic(Action <string> output)
        {
            var node     = new Uri(ElasticConstants.Endpoint);
            var settings = new ConnectionSettings(node);
            var client   = new ElasticClient(settings);

            var existsResponse = await client.IndexExistsAsync(Indices.Index(ElasticConstants.PlacesCollectionName));

            if (!existsResponse.Exists)
            {
                output?.Invoke("Index does not exist");
                var index = settings.DefaultMappingFor <Place>(x => x.IndexName(ElasticConstants.PlacesCollectionName));
                client = new ElasticClient(index);

                var indexCreate = await client.CreateIndexAsync(IndexName.From <Place>(), i =>
                                                                i.Mappings(m =>
                                                                           m.Map <Place>(mp =>
                                                                                         mp.AutoMap()
                                                                                         .Properties(p =>
                                                                                                     p.Text(t => t.Fielddata(true)
                                                                                                            .TermVector(TermVectorOption.WithPositionsOffsetsPayloads)
                                                                                                            .Name(n => n.Name))
                                                                                                     .Text(t => t.Fielddata(true)
                                                                                                           .Name(n => n.PlaceId))
                                                                                                     .Text(t => t.Fielddata(true)
                                                                                                           .TermVector(TermVectorOption.WithPositionsOffsetsPayloads)
                                                                                                           .Name(n => n.Vicinity))
                                                                                                     .Text(t => t.Fielddata(true)
                                                                                                           .Name(n => n.Types)
                                                                                                           .Fielddata(true))
                                                                                                     )
                                                                                         )));

                if (!indexCreate.Acknowledged)
                {
                    output?.Invoke("Error while creating index");
                    return;
                }
                output?.Invoke("Index created");
            }

            var places       = await new GooglePlacesService().GetDataAsync();
            var bulkResponse = client.Bulk(b =>
            {
                places.ForEach(p => b.Index <Place>(i => i.Document(p)));
                return(b);
            });

            if (bulkResponse.Errors)
            {
                foreach (var e in bulkResponse.ItemsWithErrors)
                {
                    output?.Invoke($"{e.Error.Index} - { e.Error.Reason}");
                }
            }
            output?.Invoke("Filled");
        }
Ejemplo n.º 8
0
        public async Task <TermVectorsModel> TermVectors(string queryString, double lat, double lng)
        {
            var client           = GetClient();
            var searchDescriptor = new SearchDescriptor <Place>();
            var dumper           = new NestDescriptorDumper(client.RequestResponseSerializer);

            #region Search
            QueryContainerDescriptor <Place> queryContainer = new QueryContainerDescriptor <Place>();
            var query = queryContainer.Bool(b =>
                                            b.Should(
                                                q => q.Match(m => m.Field(f => f.Name).Query(queryString)),
                                                q => q.Match(m => m.Field(f => f.Vicinity).Query(queryString))
                                                )
                                            );

            Func <SortDescriptor <Place>, SortDescriptor <Place> > SortByGeo =
                (SortDescriptor <Place> s) => s.GeoDistance(g =>
                                                            g.Field(f => f.Geometry.Location)
                                                            .DistanceType(GeoDistanceType.Arc)
                                                            .Unit(DistanceUnit.Kilometers)
                                                            .Order(SortOrder.Ascending)
                                                            .Points(new GeoLocation(lat, lng)));

            Func <SortDescriptor <Place>, IPromise <IList <ISort> > > sort = s => SortByGeo(s.Descending(SortSpecialField.Score).Descending(d => d.Rating));

            searchDescriptor
            .Index <Place>()
            .Query(x => query)
            .Sort(sort)
            .ScriptFields(x =>
                          x.ScriptField("distance", s => s.Source($"doc['geometry.location'].arcDistance({lat},{lng})")))
            .Take(10)
            .Source(true)
            ;
            #endregion

            var results = await client.SearchAsync <Place>(searchDescriptor);

            var model = ToSearchPlaces(results.Hits).First();

            var term = new TermVectorsDescriptor <Place>(IndexName.From <Place>(), TypeName.From <Place>());
            term.Index <Place>()
            .Id(Id.From(model))
            .Fields(tf => tf.Vicinity, tf => tf.Name)
            ;

            var sss = dumper.Dump <TermVectorsDescriptor <Place> >(term);

            var termVectorsResult = await client.TermVectorsAsync <Place>(term);

            return(ToTermVectorsModel(termVectorsResult, model));
        }
Ejemplo n.º 9
0
        [U] public async Task Urls()
        {
            var project = new Project {
                Name = "NEST"
            };

            await PUT("/project/_create/1")
            .Fluent(c => c.Create <object>(new { }, i => i.Index(typeof(Project)).Id(1)))
            .Request(c => c.Create(new CreateRequest <object>("project", 1)
            {
                Document = new { }
            }))
            .FluentAsync(c => c.CreateAsync <object>(new { }, i => i.Index(typeof(Project)).Id(1)))
            .RequestAsync(c => c.CreateAsync(new CreateRequest <object>(IndexName.From <Project>(), 1)
            {
                Document = new { }
            }));

            await PUT("/project/_create/NEST")
            .Fluent(c => c.CreateDocument(project))
            .Fluent(c => c.Create(project, f => f))
            .Request(c => c.Create(new CreateRequest <Project>(project)))
            .FluentAsync(c => c.CreateDocumentAsync(project))
            .FluentAsync(c => c.CreateAsync(project, f => f))
            .RequestAsync(c => c.CreateAsync(new CreateRequest <Project>(project)));

            await PUT("/project2/_create/NEST")
            .Fluent(c => c.Create(project, cc => cc.Index("project2")))
            .Request(c => c.Create(new CreateRequest <Project>(project, "project2", "NEST")
            {
                Document = project
            }))
            .RequestAsync(c => c.CreateAsync(new CreateRequest <Project>(project, "project2", "NEST")
            {
                Document = project
            }))
            .FluentAsync(c => c.CreateAsync(project, cc => cc.Index("project2")));

            await PUT("/different-projects/_create/elasticsearch")
            .Request(c => c.Create(new CreateRequest <Project>("different-projects", "elasticsearch")
            {
                Document = project
            }))
            .Request(c => c.Create(new CreateRequest <Project>(project, "different-projects", "elasticsearch")))
            .RequestAsync(c => c.CreateAsync(new CreateRequest <Project>(project, "different-projects", "elasticsearch")))
            .RequestAsync(c => c.CreateAsync(new CreateRequest <Project>("different-projects", "elasticsearch")
            {
                Document = project
            }))
            ;
        }
Ejemplo n.º 10
0
        /**[[indices-paths]]
         * === Indices paths
         *
         * Some APIs in Elasticsearch take an index name, a collection of index names,
         * or the special `_all` marker (used to specify all indices), in the URI path of the request, to specify the indices that
         * the request should execute against.
         *
         * In NEST, these index names can be specified using the `Indices` type.
         *
         * ==== Implicit Conversion
         *
         * To make working with `Indices` easier, several types implicitly convert to it:
         *
         * - `string`
         * - comma separated `string`
         * - `string` array
         * - a CLR type, <<index-name-inference, where a default index name or index name for the type has been specified on `ConnectionSettings`>>
         * - `IndexName`
         * - `IndexName` array
         *
         * Here are some examples of how implicit conversions can be used to specify index names
         */
        [U] public void ImplicitConversions()
        {
            Nest.Indices singleIndexFromString          = "name";
            Nest.Indices multipleIndicesFromString      = "name1, name2";
            Nest.Indices multipleIndicesFromStringArray = new [] { "name1", "name2" };
            Nest.Indices allFromString = "_all";

            Nest.Indices allWithOthersFromString = "_all, name2";           //<1> `_all` will override any specific index names here

            Nest.Indices singleIndexFromType = typeof(Project);             //<2> The `Project` type has been mapped to a specific index name using <<index-name-type-mapping,`.DefaultMappingFor<Project>`>>

            Nest.Indices singleIndexFromIndexName = IndexName.From <Project>();

            singleIndexFromString.Match(
                all => all.Should().BeNull(),
                many => many.Indices.Should().HaveCount(1).And.Contain("name")
                );

            multipleIndicesFromString.Match(
                all => all.Should().BeNull(),
                many => many.Indices.Should().HaveCount(2).And.Contain("name2")
                );

            allFromString.Match(
                all => all.Should().NotBeNull(),
                many => many.Indices.Should().BeNull()
                );

            allWithOthersFromString.Match(
                all => all.Should().NotBeNull(),
                many => many.Indices.Should().BeNull()
                );

            multipleIndicesFromStringArray.Match(
                all => all.Should().BeNull(),
                many => many.Indices.Should().HaveCount(2).And.Contain("name2")
                );

            singleIndexFromType.Match(
                all => all.Should().BeNull(),
                many => many.Indices.Should().HaveCount(1).And.Contain(typeof(Project))
                );

            singleIndexFromIndexName.Match(
                all => all.Should().BeNull(),
                many => many.Indices.Should().HaveCount(1).And.Contain(typeof(Project))
                );
        }
Ejemplo n.º 11
0
        public static IElasticClient Create()
        {
            var settings = new ConnectionSettings()
                           //.ThrowExceptions()
                           .DisableDirectStreaming()
                           .DefaultMappingFor <Channel>(m => m.IndexName("chat-channels"))
                           .DefaultMappingFor <UserAccount>(m => m.IndexName("chat-users"))
                           .DefaultMappingFor <Sentence>(m => m.IndexName("chat-sentences"));

            var client = new ElasticClient(settings);

            var existResponse = client.Indices.Exists(IndexName.From <Sentence>());

            if (!existResponse.Exists)
            {
                client.Indices.Create(IndexName.From <Sentence>(), c => c
                                      .Settings(m => m
                                                .Analysis(a => a
                                                          .Normalizers(p => p.Custom("lowercase", f => f.Filters("lowercase")))))
                                      .Map <Sentence>(m => m.AutoMap <Sentence>()));
            }

            existResponse = client.Indices.Exists(IndexName.From <UserAccount>());

            if (!existResponse.Exists)
            {
                client.Indices.Create(IndexName.From <UserAccount>(), c => c
                                      .Settings(m => m
                                                .Analysis(a => a
                                                          .Normalizers(p => p.Custom("lowercase", f => f.Filters("lowercase")))))

                                      .Map <UserAccount>(m => m.AutoMap <UserAccount>()));
            }

            existResponse = client.Indices.Exists(IndexName.From <Channel>());

            if (!existResponse.Exists)
            {
                client.Indices.Create(IndexName.From <Channel>(), c => c
                                      .Settings(m => m
                                                .Analysis(a => a
                                                          .Normalizers(p => p.Custom("lowercase", f => f.Filters("lowercase")))))
                                      .Map <Channel>(m => m.AutoMap <Channel>()));
            }

            return(client);
        }
Ejemplo n.º 12
0
        public async Task CleanElastic(Action <string> output)
        {
            var node     = new Uri(ElasticConstants.Endpoint);
            var settings = new ConnectionSettings(node);
            var client   = new ElasticClient(settings);

            var existsResponse = await client.IndexExistsAsync(Indices.Index(ElasticConstants.PlacesCollectionName));

            if (existsResponse.Exists)
            {
                var index = settings.DefaultMappingFor <Place>(x => x.IndexName(ElasticConstants.PlacesCollectionName));
                client = new ElasticClient(index);
                var indexDelete = await client.DeleteIndexAsync(IndexName.From <Place>());

                if (!indexDelete.Acknowledged)
                {
                    output?.Invoke("Error while deleting index");
                    return;
                }
                output?.Invoke("Index deleted");
            }
        }
Ejemplo n.º 13
0
        [U] public void UsingWithRequests()
        {
            var project = new Project {
                Name = "hello-world"
            };

            /** Here we can see and example how DocumentPath helps your describe your requests more tersely */
            var request = new IndexRequest <Project>(2)
            {
                Document = project
            };

            request = new IndexRequest <Project>(project)
            {
            };

            /** when comparing with the full blown constructor and passing document manually
             * DocumentPath&lt;T&gt;'s benefits become apparent.
             */
            request = new IndexRequest <Project>(IndexName.From <Project>(), TypeName.From <Project>(), 2)
            {
                Document = project
            };
        }
Ejemplo n.º 14
0
 public static IndexName Index <T>(string clusterName) => IndexName.From <T>(clusterName);
Ejemplo n.º 15
0
        [U] public async Task Urls()
        {
            var name  = "name-of-perc";
            var index = "indexx";

            await POST($"/{index}/.percolator/{name}")
            .Fluent(c => c.RegisterPercolator <Project>(name, s => s.Index(index)))
            .Request(c => c.RegisterPercolator(new RegisterPercolatorRequest(index, name)))
            .FluentAsync(c => c.RegisterPercolatorAsync <Project>(name, s => s.Index(index)))
            .RequestAsync(c => c.RegisterPercolatorAsync(new RegisterPercolatorRequest(index, name)))
            ;

            await POST($"/project/.percolator/{name}")
            .Fluent(c => c.RegisterPercolator <Project>(name, s => s))
            .Request(c => c.RegisterPercolator(new RegisterPercolatorRequest(typeof(Project), name)))
            .FluentAsync(c => c.RegisterPercolatorAsync <Project>(name, s => s))
            .RequestAsync(c => c.RegisterPercolatorAsync(new RegisterPercolatorRequest(IndexName.From <Project>(), name)))
            ;
        }
        private void CreateIndex()
        {
            var postIndex = IndexName.From <Post>();

            #region Default Analyzer
            //var aaa = elasticClient.Indices.UpdateSettings(postIndex, p => p
            //    .IndexSettings(p => p
            //        .Analysis(p => p
            //            .Analyzers(p => p
            //                .UserDefined("default", new SimpleAnalyzer())
            //            )
            //        )
            //    )
            //);
            //Request:
            //PUT http://localhost:9200/my-post-index/_settings?pretty=true&error_trace=true
            //{
            //  "analysis": {
            //    "analyzer": {
            //      "default": {
            //        "type": "simple"
            //      }
            //    }
            //  }
            //}

            //var bbb = elasticClient.Indices.Create(postIndex, p => p
            //    .Settings(p => p
            //        .Analysis(p => p
            //            .Analyzers(p => p
            //                .UserDefined("default", new SimpleAnalyzer())
            //            )
            //        )
            //    )
            //);
            //Request:
            //PUT http://localhost:9200/my-post-index?pretty=true&error_trace=true
            //{
            //  "settings": {
            //    "analysis": {
            //      "analyzer": {
            //        "default": {
            //          "type": "simple"
            //        }
            //      }
            //    }
            //  }
            //}
            #endregion

            //### Delete
            var deleteIndexResponse = elasticClient.Indices.Delete(postIndex);

            //### Create Index
            var stopwordsPath = Path.Combine(Directory.GetCurrentDirectory(), "stopwords.txt");

            //var stopwords = File.ReadAllLines(stopwordsPath).Select(p => p.Trim());
            var stopwords = new[] {
                "جامع",
                "آرام",
                "میرود",
                "کردند",
                "123"
            };

            #region Persian & Arabic Analyzer/Normalizer
            //Persian Chars
            //Normalizer: https://github.com/apache/lucenenet/blob/master/src/Lucene.Net.Analysis.Common/Analysis/Fa/PersianNormalizer.cs
            //YEH_FARSI	        (char)1740 == '\u06CC'	    'ی'
            //YEH		        (char)1610 == '\u064A'	    'ي'
            //YEH_BARREE	    (char)1746 == '\u06D2'	    'ے'
            //HEH (farsi)	    (char)1607 == '\u0647'	    'ه'
            //HEH_YEH		    (char)1728 == '\u06C0'	    'ۀ'
            //HEH_GOAL	        (char)1729 == '\u06C1'	    'ہ'
            //KEHEH             (char)1705 == '\u06A9'	    'ک'
            //KAF		        (char)1603 == '\u0643'	    'ك'
            //HAMZA_ABOVE       (char)1620 == '\u0654'	    'ٔ'
            //ZERO_SPACE        (char)8204 == '\u200C'      '‌'
            //NORMAL_SPACE      (char)32   == '\u0020'      ' '

            //Persian Fixing
            //YEH		        "\\u064A=>\\u06CC"          'ي' => 'ی'
            //YEH_BARREE	    "\\u06D2=>\\u06CC"          'ے' => 'ی'
            //KAF		        "\\u0643=>\\u06A9"          'ك' => 'ک'
            //HEH_YEH	        "\\u06C0=>\\u0647"          'ۀ' => 'ه'
            //HEH_GOAL	        "\\u06C1=>\\u0647"          'ہ' => 'ه'
            //HAMZA_ABOVE       REMOVE "\\u0654=>"          'ٔ'

            //Arabic Chars (except persians)
            //Normalizer: https://github.com/apache/lucenenet/blob/master/src/Lucene.Net.Analysis.Common/Analysis/Ar/ArabicNormalizer.cs
            //ALEF              (char)1575 == '\u0627'      'ا'
            //ALEF_MADDA        (char)1570 == '\u0622'      'آ'
            //ALEF_HAMZA_ABOVE  (char)1571 == '\u0623'      'أ'
            //ALEF_HAMZA_BELOW  (char)1573 == '\u0625'      'إ'
            //DOTLESS_YEH       (char)1609 == '\u0649'      'ى'
            //TEH_MARBUTA       (char)1577 == '\u0629'      'ة'
            //TATWEEL           (char)1600 == '\u0640'      'ـ' (KhateTire)
            //FATHA             (char)1614 == '\u064E'      'َ' (Fathe)
            //FATHATAN          (char)1611 == '\u064B'      'ً' (TanvinFathe)
            //DAMMA             (char)1615 == '\u064F'      'ُ' (Zamme)
            //DAMMATAN          (char)1612 == '\u064C'      'ٌ' (TanvinZamme)
            //KASRA             (char)1616 == '\u0650'      'ِ' (Kasre)
            //KASRATAN          (char)1613 == '\u064D'      'ٍ' (TanvinKasre)
            //SHADDA            (char)1617 == '\u0651'      'ّ' (Tashdid)
            //SUKUN             (char)1618 == '\u0652'      'ْ' (Sokun)

            //Arabic Fixing
            //ALEF_MADDA        "\\u0622=>\\u0627"          'آ' => 'ا'
            //ALEF_HAMZA_ABOVE  "\\u0623=>\\u0627"          'أ' => 'ا'
            //ALEF_HAMZA_BELOW  "\\u0625=>\\u0627"          'إ' => 'ا'
            //DOTLESS_YEH       "\\u0649=>\\u06CC"          'ى' => 'ی'  (original normalizer replaces with \u064A 'ي')
            //TEH_MARBUTA       "\\u0629=>\\u0647"          'ة' => 'ه'
            //TATWEEL           REMOVE "\\u0640=>"          'ـ' (KhateTire)
            //FATHA             REMOVE "\\u064E=>"          'َ' (Fathe)
            //FATHATAN          REMOVE "\\u064B=>"          'ً' (TanvinFathe)
            //DAMMA             REMOVE "\\u064F=>"          'ُ' (Zamme)
            //DAMMATAN          REMOVE "\\u064C=>"          'ٌ' (TanvinZamme)
            //KASRA             REMOVE "\\u0650=>"          'ِ' (Kasre)
            //KASRATAN          REMOVE "\\u064D=>"          'ٍ' (TanvinKasre)
            //SHADDA            REMOVE "\\u0651=>"          'ّ' (Tashdid)
            //SUKUN             REMOVE "\\u0652=>"          'ْ' (Sokun)

            //Arab Ameri Chars
            //Normalizer: https://github.com/SalmanAA/Lucene.Net.Analysis.Fa/blob/master/Lucene.Net.Analysis.Fa/PersianNormalizer.cs
            //Stemer    : https://github.com/SalmanAA/Lucene.Net.Analysis.Fa/blob/master/Lucene.Net.Analysis.Fa/PersianStemmer.cs
            //HAMZE_JODA        (char)1569 == '\u0621'      'ء' (HamzeJoda)

            //Arab Ameri Fixing
            //HAMZE_JODA        REMOVE "\\u0621=>"          'ء' (HamzeJoda)



            //var createIndexResponse = elasticClient.Indices.Create(postIndex, p => p
            //    .Settings(p => p
            //        .Analysis(p => p
            //            .CharFilters(p => p
            //                //https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-mapping-charfilter.html
            //                .Mapping("mapping_filter", p => p
            //                    .Mappings(
            //                        "\\u200C=>\\u0020"//, //Fix ZERO_SPACE
            //                                          //"\\u064A=>\\u06CC", //Fix YEH
            //                                          //"\\u06D2=>\\u06CC", //Fix YEH_BARREE
            //                                          //"\\u0649=>\\u06CC", //Fix DOTLESS_YEH
            //                                          //"\\u0643=>\\u06A9", //Fix KAF
            //                                          //"\\u06C0=>\\u0647", //Fix HEH_YEH
            //                                          //"\\u06C1=>\\u0647", //Fix HEH_GOAL
            //                                          //"\\u0629=>\\u0647", //Fix TEH_MARBUTA
            //                                          //"\\u0622=>\\u0627", //Fix ALEF_MADDA
            //                                          //"\\u0623=>\\u0627", //Fix ALEF_HAMZA_ABOVE
            //                                          //"\\u0625=>\\u0627", //Fix ALEF_HAMZA_BELOW
            //                                          //"\\u0654=>",        //Remove HAMZA_ABOVE
            //                                          //"\\u0640=>",        //Remove TATWEEL
            //                                          //"\\u064E=>",        //Remove FATHA
            //                                          //"\\u064B=>",        //Remove FATHATAN
            //                                          //"\\u064F=>",        //Remove DAMMA
            //                                          //"\\u064C=>",        //Remove DAMMATAN
            //                                          //"\\u0650=>",        //Remove KASRA
            //                                          //"\\u064D=>",        //Remove KASRATAN
            //                                          //"\\u0651=>",        //Remove SHADDA
            //                                          //"\\u0652=>"         //Remove SUKUN
            //                                          //"\\u0621=>"         //Remove HAMZE_JODA
            //                    )
            //                )
            //            )
            //            .TokenFilters(p => p
            //                //https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-stop-tokenfilter.html
            //                .Stop("persian_stop", p => p
            //                    .StopWords(stopwords)
            //                    .RemoveTrailing()
            //                //.IgnoreCase()
            //                )
            //                .PatternReplace("fix-YEH", p => p.Pattern("\u064A").Replacement("\u06CC"))
            //                .PatternReplace("fix-YEH_BARREE", p => p.Pattern("\u06D2").Replacement("\u06CC"))
            //                .PatternReplace("fix-DOTLESS_YEH", p => p.Pattern("\u0649").Replacement("\u06CC"))
            //                .PatternReplace("fix-KAF", p => p.Pattern("\u0643").Replacement("\u06A9"))
            //                .PatternReplace("fix-HEH_YEH", p => p.Pattern("\u06C0").Replacement("\u0647"))
            //                .PatternReplace("fix-HEH_GOAL", p => p.Pattern("\u06C1").Replacement("\u0647"))
            //                .PatternReplace("fix-TEH_MARBUTA", p => p.Pattern("\u0629").Replacement("\u0647"))
            //                .PatternReplace("fix-ALEF_MADDA", p => p.Pattern("\u0622").Replacement("\u0627"))
            //                .PatternReplace("fix-ALEF_HAMZA_ABOVE", p => p.Pattern("\u0623").Replacement("\u0627"))
            //                .PatternReplace("fix-ALEF_HAMZA_BELOW", p => p.Pattern("\u0625").Replacement("\u0627"))
            //                .PatternReplace("remove-HAMZA_ABOVE", p => p.Pattern("\u0654").Replacement(string.Empty))
            //                .PatternReplace("remove-TATWEEL", p => p.Pattern("\u0640").Replacement(string.Empty))
            //                .PatternReplace("remove-FATHA", p => p.Pattern("\u064E").Replacement(string.Empty))
            //                .PatternReplace("remove-FATHATAN", p => p.Pattern("\u064B").Replacement(string.Empty))
            //                .PatternReplace("remove-DAMMA", p => p.Pattern("\u064F").Replacement(string.Empty))
            //                .PatternReplace("remove-DAMMATAN", p => p.Pattern("\u064C").Replacement(string.Empty))
            //                .PatternReplace("remove-KASRA", p => p.Pattern("\u0650").Replacement(string.Empty))
            //                .PatternReplace("remove-KASRATAN", p => p.Pattern("\u064D").Replacement(string.Empty))
            //                .PatternReplace("remove-SHADDA", p => p.Pattern("\u0651").Replacement(string.Empty))
            //                .PatternReplace("remove-SUKUN", p => p.Pattern("\u0652").Replacement(string.Empty))
            //                .PatternReplace("remove-HAMZE_JODA", p => p.Pattern("\u0621").Replacement(string.Empty))
            //            )
            //            .Analyzers(p => p
            //                .Custom("persian_analyzer", p => p
            //                    .Tokenizer("standard") //https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-standard-tokenizer.html
            //                    .CharFilters(
            //                        "html_strip", //https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-htmlstrip-charfilter.html
            //                        "mapping_filter"
            //                    )
            //                    .Filters(
            //                        "lowercase", //https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-lowercase-tokenfilter.html
            //                        "decimal_digit", //https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-decimal-digit-tokenfilter.html
            //                        "persian_stop",

            //                        //"arabic_normalization", //https://lucene.apache.org/core/8_8_0/analyzers-common/org/apache/lucene/analysis/ar/ArabicNormalizer.html
            //                        //"persian_normalization", //https://lucene.apache.org/core/8_8_0/analyzers-common/org/apache/lucene/analysis/fa/PersianNormalizer.html
            //                        "fix-YEH",
            //                        "fix-YEH_BARREE",
            //                        "fix-DOTLESS_YEH",
            //                        "fix-KAF",
            //                        "fix-HEH_YEH",
            //                        "fix-HEH_GOAL",
            //                        "fix-TEH_MARBUTA",
            //                        "fix-ALEF_MADDA",
            //                        "fix-ALEF_HAMZA_ABOVE",
            //                        "fix-ALEF_HAMZA_BELOW",
            //                        "remove-HAMZA_ABOVE",
            //                        "remove-TATWEEL",
            //                        "remove-FATHA",
            //                        "remove-FATHATAN",
            //                        "remove-DAMMA",
            //                        "remove-DAMMATAN",
            //                        "remove-KASRA",
            //                        "remove-KASRATAN",
            //                        "remove-SHADDA",
            //                        "remove-SUKUN",
            //                        "remove-SUKUN",
            //                        "remove-HAMZE_JODA",

            //                        "persian_stop" //remove stopwords before and after normalizations because of ('آ' => 'ا')
            //                    )
            //                )
            //            )
            //        )
            //    )
            //    .Map<Post>(p => p
            //        .AutoMap()
            //        .Properties(p => p
            //            //.Number(p => p.Name(p => p.Id))
            //            .Text(p => p
            //                .Name(p => p.Title)
            //                .Analyzer("persian_analyzer")
            //            )
            //            .Text(p => p
            //                .Name(p => p.Body)
            //                .Analyzer("persian_analyzer")
            //            //.SearchAnalyzer("persian_analyzer")
            //            //.Boost(1.5)
            //            //.Store(true)
            //            //.Index(true)
            //            //.Norms(true)
            //            //.IndexPhrases(true)
            //            //.IndexOptions(IndexOptions.Offsets)
            //            //.TermVector(TermVectorOption.WithPositionsOffsetsPayloads)
            //            )
            //        )
            //    )
            //);
            #endregion

            var createIndexResponse = elasticClient.Indices.Create(postIndex, p => p
                                                                   .Settings(p => p
                                                                             .Analysis(p => p
                                                                                       .CharFilters(p => p
                                                                                                    .Mapping("mapping_filter", p => p
                                                                                                             .Mappings(
                                                                                                                 "\\u200C=>\\u0020" //Fix ZERO_SPACE
                                                                                                                 )
                                                                                                             )
                                                                                                    )
                                                                                       .TokenFilters(p => p
                                                                                                     .Stop("persian_stop", p => p
                                                                                                           .StopWords(new StopWords("_persian_"))
                                                                                                           .RemoveTrailing()
                                                                                                           )
                                                                                                     )
                                                                                       .Analyzers(p => p
                                                                                                  .Custom("persian_analyzer", p => p
                                                                                                          .Tokenizer("standard")
                                                                                                          .CharFilters(
                                                                                                              "html_strip",
                                                                                                              "mapping_filter"
                                                                                                              )
                                                                                                          .Filters(
                                                                                                              "lowercase",
                                                                                                              "decimal_digit",
                                                                                                              "arabic_normalization",
                                                                                                              "persian_normalization",
                                                                                                              "persian_stop"
                                                                                                              )
                                                                                                          )
                                                                                                  )
                                                                                       )
                                                                             )
                                                                   .Map <Post>(p => p
                                                                               .AutoMap()
                                                                               .Properties(p => p
                                                                                           .Text(p => p
                                                                                                 .Name(p => p.Title)
                                                                                                 .Analyzer("persian_analyzer")
                                                                                                 //.Boost(1.5)
                                                                                                 )
                                                                                           .Text(p => p
                                                                                                 .Name(p => p.Body)
                                                                                                 .Analyzer("persian_analyzer")
                                                                                                 //.Boost(1.0)
                                                                                                 //.Store(true)
                                                                                                 //.Index(true)
                                                                                                 //.Norms(true)
                                                                                                 //.IndexPhrases(true)
                                                                                                 //.IndexOptions(IndexOptions.Offsets)
                                                                                                 //.TermVector(TermVectorOption.WithPositionsOffsetsPayloads)
                                                                                                 )
                                                                                           )
                                                                               )
                                                                   );

            //Request:
            //PUT /my-post-index?pretty=true&error_trace=true
            //{
            //  "mappings": {
            //    "properties": {
            //      "id": {
            //        "type": "integer"
            //      },
            //      "title": {
            //        "analyzer": "persian_analyzer",
            //        "boost": 1.5,
            //        "type": "text"
            //      },
            //      "body": {
            //        "analyzer": "persian_analyzer",
            //        "boost": 1.0,
            //        "type": "text"
            //      }
            //    }
            //  },
            //  "settings": {
            //    "analysis": {
            //      "analyzer": {
            //        "persian_analyzer": {
            //          "char_filter": [
            //            "html_strip",
            //            "mapping_filter"
            //          ],
            //          "filter": [
            //            "lowercase",
            //            "decimal_digit",
            //            "arabic_normalization",
            //            "persian_normalization",
            //            "persian_stop"
            //          ],
            //          "tokenizer": "standard",
            //          "type": "custom"
            //        }
            //      },
            //      "char_filter": {
            //        "mapping_filter": {
            //          "mappings": [
            //            "\\u200C=>\\u0020"
            //          ],
            //          "type": "mapping"
            //        }
            //      },
            //      "filter": {
            //        "persian_stop": {
            //          "remove_trailing": true,
            //          "stopwords": "_persian_",
            //          "type": "stop"
            //        }
            //      }
            //    }
            //  }
            //}
        }