使用NEST和Elastic Search来创建到文档字段的分析器映射

本文关键字:字段 文档 分析器 映射 创建 NEST Elastic Search 使用 | 更新日期: 2023-09-27 18:19:43

我使用的是NEST 0.11.0.0和示例代码blow。这段代码成功地创建了索引,但我的搜索查询不起作用。我希望能够用类似"14-KP-OM-00368"的短划线搜索产品代码。我在这里错过了什么?

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using ElasticSearchSample.Data;
using Nest;
namespace ElasticSearchSample
{
    class Program
    {
        static void Main(string[] args)
        {
            const string keyName = "products";
            var typeName = typeof(ProductEntity).ToString();
            var setting = new ConnectionSettings(new Uri("http://localhost:3330/"));
            setting.SetDefaultIndex("products");
            var elasticClient = new ElasticClient(setting);
            var products = GetProducts();
            foreach (var product in products)
            {
                elasticClient.MapFromAttributes<ProductEntity>();
                var settings = new IndexSettings { NumberOfReplicas = 0, NumberOfShards = 5 };
                settings.Analysis.Tokenizers.Add("keyword", new KeywordTokenizer());
                settings.Analysis.Tokenizers.Add("standard", new StandardTokenizer());
                settings.Analysis.TokenFilters.Add("standard", new StandardTokenFilter());
                settings.Analysis.TokenFilters.Add("lowercase", new LowercaseTokenFilter());
                settings.Analysis.TokenFilters.Add("stop", new StopTokenFilter());
                settings.Analysis.TokenFilters.Add("asciifolding", new AsciiFoldingTokenFilter());
                settings.Analysis.TokenFilters.Add("word_delimiter", new WordDelimiterTokenFilter());
                if (!elasticClient.IndexExists(keyName).Exists)
                    elasticClient.CreateIndex(keyName, settings);
                elasticClient.DeleteById(keyName, typeName, product.Identifier.ToString(), new DeleteParameters { Refresh = true });
                elasticClient.Index(product, keyName, typeName, product.Identifier.ToString(), new IndexParameters { Refresh = true });
            }
            var sp1 = Stopwatch.StartNew();
            //Search part 
            var result = elasticClient.Search<ProductEntity>(body => body.Type(typeName)
                                                                            .Fields(f => f.ProductCode).Query(q => q
                                                                            .Term(f => f.ProductCode.ToLower(), "14 kp om 01567", 2.0)));
            // I searched via lower case char without dash, with dash but no luck
            // but I want want to search with dash
            Console.WriteLine("ES Results : {0:#,#} documents in {1:#,#}ms: {2:#,#.##}: docs/ms'n'n", result.Documents.Count(), sp1.ElapsedMilliseconds, result.Documents.Count() / (double)sp1.ElapsedMilliseconds);
            Console.ReadLine();
        }
        public static List<ProductEntity> GetProducts()
        {
            var list = new List<ProductEntity> {
                                                        new ProductEntity {CreatedDate = new DateTime(2013, 6, 25),Identifier = Guid.NewGuid(),IsActive = true,ProductCode = "14-KP-OM-00368", ProductName = "Şemsiye", SortOrder = 1}, 
                                                        new ProductEntity {CreatedDate = new DateTime(2013, 6, 25),Identifier = Guid.NewGuid(),IsActive = true,ProductCode = "14-KP-OM-01567", ProductName = "Çeşme",SortOrder = 2 }
                                                    };
            return list;
        }
    }
}
namespace ElasticSearchSample.Data
{
    [ElasticType(Name = "ElasticSearchSample.Data.ProductEntity", SearchAnalyzer = "full_name", IndexAnalyzer = "partial_name", DateDetection = true, NumericDetection = true, DynamicDateFormats = new[] { "dateOptionalTime", "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd Z" })]
    public class ProductEntity
    {
        [ElasticProperty(Type = FieldType.string_type, Index = FieldIndexOption.analyzed)]
        public Guid Identifier { get; set; }
        [ElasticProperty(Type = FieldType.string_type, Index = FieldIndexOption.analyzed)]
        public string ProductCode { get; set; }
        [ElasticProperty(Type = FieldType.string_type, Index = FieldIndexOption.analyzed)]
        public string ProductName { get; set; }
        [ElasticProperty(Type = FieldType.boolean_type, Index = FieldIndexOption.analyzed)]
        public bool IsActive { get; set; }
        [ElasticProperty(Type = FieldType.integer_type, Index = FieldIndexOption.analyzed)]
        public int? SortOrder { get; set; }
        [ElasticProperty(Type = FieldType.date_type, Index = FieldIndexOption.analyzed)]
        public DateTime CreatedDate { get; set; }
    }
}

使用NEST和Elastic Search来创建到文档字段的分析器映射

您正在创建分析器,但从未告诉elasticsearch ProductType使用什么,因此将使用默认分析器,该分析器将14-KP-OM-00368分解为:

  • 14
  • kp
  • om
  • 00368

如果您为14 kp om 00368发出一个术语查询,它将无法找到它,因为它试图将其作为一个术语,而上一个列表不包含该术语。

你想做以下事情:

client.CreateIndex(keyName, c => c
    .NumberOfReplicas(0)
    .NumberOfShards(1)
    .Settings(s=>s //just as an example
        .Add("merge.policy.merge_factor","10")
        .Add("search.slowlog.threshold.fetch.warn", "1s")
    )   
    .AddMapping<ProductEntity>(m => m
        //this will explicitly map all the properties it finds
        //so es knows in advance Date's are dates, ints are int's
        //This will also apply ElasticType attributes
        .MapFromAttributes()
        //here we inform es our propertyType field is to be analyzed
        //using the keyword analyzers
        .Properties(props => props
            .String(s => s
                .Name(p => p.PropertyType)
                .IndexAnalyzer("keyword")
            )
        )
    )
    //just to show you can map more types at once
    .AddMapping<Person>(m => m.MapFromAttributes()) 
);

现在keyword分析器处于活动状态,它不会分解属性的值并按原样进行处理,现在您可以使用术语14-KP-OM-00368

还要注意,您不需要像在示例中那样将默认分析器添加到索引中,关键字分析器已经可用。