【问题标题】:Elasticsearch NEST: partial/full-text search without wildcardElasticsearch NEST:不带通配符的部分/全文搜索
【发布时间】:2016-10-03 13:18:04
【问题描述】:

我想为我的用户创建一个搜索引擎。假设用户类是:

public class User
{
    public string Code { get; set; }
    public string Name { get; set; }
}

我的数据库中有这样的用户:

(1) new User { Code = "XW1234", Name = "John Doe" }, 
(2) new User { Code = "AD4567", Name = "Jane Doe" }

所以: 当我的查询是:“doe”(注意小写)时,我想查看 (1) 和 (2) 当我的查询是:“4”时,我想查看 (1) 和 (2) 当我的查询是:“x”我想看 (1) 当我的查询是:“ja”我想看 (2) 我想在 SQL 中与like %doe% 类似地工作。请不要介意查询长度 - 我将使用最少 3 个字母。这只是一个例子。

我有一个使用通配符的解决方案 - 有效,但性能很差。

我试图将索引配置为使用 ngram 标记器,但没有成功 - 我收到一个空集合。

我也检查了这个(“开始”方法): https://www.elastic.co/guide/en/elasticsearch/guide/current/_index_time_search_as_you_type.html 没有成功。

请提供 C# 代码。我不知道我是否正确翻译了 Elastic 搜索 json。

编辑 根据第一条评论,我尝试了这个:

private const string DefaultIndexName = "test";
private const string ElasticSearchServerUri = @"http://192.168.99.100:32769";

private static readonly IndexName UsersIndexName = "users";

public IElasticClient CreateElasticClient()
{
    var settings = CreateConnectionSettings();

    var client = new ElasticClient(settings);

    var studentsIndexDescriptor = new CreateIndexDescriptor(UsersIndexName)
        .Mappings(ms => ms
            .Map<User>(m => m
                .Properties(ps => ps
                    .String(s => s
                        .Name(n => n.Code)
                        .Analyzer("substring_analyzer")))));
    client.CreateIndex(UsersIndexName, descriptor => studentsIndexDescriptor
        .Settings(s => s
            .Analysis(a => a
                .Analyzers(analyzer => analyzer
                    .Custom("substring_analyzer", analyzerDescriptor => analyzerDescriptor.Tokenizer("standard").Filters("lowercase", "substring")))
                .TokenFilters(tf => tf
                    .NGram("substring", filterDescriptor => filterDescriptor.MinGram(2).MaxGram(15))))));

    return client;
}

private static ConnectionSettings CreateConnectionSettings()
{
    var uri = new Uri(ElasticSearchServerUri);
    var settings = new ConnectionSettings(uri);
    settings
        .DefaultIndex(DefaultIndexName);

    return settings;
}

我使用了这个查询:

public IEnumerable<User> Search(string query)
{
    var result = elasticClient.Search<User>(descriptor => descriptor
        .Query(q => q
            .QueryString(queryDescriptor => queryDescriptor.Query(query).Fields(fs => fs.Fields(f1 => f1.Code)))));
    return result.Documents;
}

没用。

我尝试了代码:“1234”和“5678”。我尝试用“23”、“5”查询 - 没有结果。 当我搜索“1234”时,它会返回正确的用户。

【问题讨论】:

  • 您需要使用 ngram 令牌过滤器。这个答案可能会有所帮助:stackoverflow.com/questions/34331249/…
  • “请提供 C# 代码”。你都尝试了些什么?你能用 NGram 标记器/NGram 标记过滤器展示你的尝试吗?
  • @RussCam - 我添加了一个例子

标签: c# .net elasticsearch nest


【解决方案1】:

我怀疑在你的代码中:

  1. 索引用户时,您没有指定users索引,因此用户被索引到默认索引中。
  2. 搜索时,您没有指定users 索引,因此将查询默认索引test。此索引包含已索引的文档,但 code 字段不会使用 substring_analyzer 进行分析,因为此分析是在 users 索引中定义的。

NEST 在ConnectionSettings.InferMappingFor&lt;T&gt;() 上提供了一个配置选项,用于将特定的 POCO 类型与特定的索引名称相关联;如果请求中未指定索引,则将使用此索引,并优先于默认索引。

var uri = new Uri(ElasticSearchServerUri);
var settings = new ConnectionSettings(uri)
    .DefaultIndex(DefaultIndexName)
    .InferMappingFor<User>(d => d
        .IndexName(UsersIndexName)
    );

您的代码的其余部分是正确的。这是一个完整的工作示例

private const string DefaultIndexName = "test";
private const string ElasticSearchServerUri = @"http://localhost:9200";
private const string UsersIndexName = "users";

void Main()
{
    var client = CreateElasticClient();

    var users = new[] {
        new User { Code = "XW1234", Name = "John Doe" },
        new User { Code = "AD4567", Name = "Jane Doe" }
    };

    client.IndexMany(users);

    // refresh the index after indexing so that the documents are immediately 
    // available for search. This is good for testing, 
    // but avoid doing it in production.
    client.Refresh(UsersIndexName);

    var result = client.Search<User>(descriptor => descriptor
        .Query(q => q
            .QueryString(queryDescriptor => queryDescriptor
                .Query("1234")
                .Fields(fs => fs
                    .Fields(f1 => f1.Code)
                )
            )
        )
    );

    // outputs 1
    Console.WriteLine(result.Total);
}

public class User
{
    public string Code { get; set; }
    public string Name { get; set; }
}

public IElasticClient CreateElasticClient()
{
    var settings = CreateConnectionSettings();
    var client = new ElasticClient(settings);

    // this is here so that the example can be re-run.
    // Remove this!
    if (client.IndexExists(UsersIndexName).Exists)
    {
        client.DeleteIndex(UsersIndexName);
    }

    client.CreateIndex(UsersIndexName, descriptor => descriptor
        .Mappings(ms => ms
            .Map<User>(m => m
                .AutoMap()
                .Properties(ps => ps
                    .String(s => s
                        .Name(n => n.Code)
                        .Analyzer("substring_analyzer")
                    )
                )
            )
        )
        .Settings(s => s
            .Analysis(a => a
                .Analyzers(analyzer => analyzer
                    .Custom("substring_analyzer", analyzerDescriptor => analyzerDescriptor
                        .Tokenizer("standard")
                        .Filters("lowercase", "substring")
                    )
                )
                .TokenFilters(tf => tf
                    .NGram("substring", filterDescriptor => filterDescriptor
                        .MinGram(2)
                        .MaxGram(15)
                    )
                )
            )
        )
    );

    return client;
}

private static ConnectionSettings CreateConnectionSettings()
{
    var uri = new Uri(ElasticSearchServerUri);
    var settings = new ConnectionSettings(uri)
        .DefaultIndex(DefaultIndexName)
        .InferMappingFor<User>(d => d
            .IndexName(UsersIndexName)
        );

    return settings;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-04-26
    • 1970-01-01
    • 2016-08-11
    • 1970-01-01
    • 1970-01-01
    • 2015-03-15
    • 2015-06-26
    • 2013-09-11
    相关资源
    最近更新 更多