Elasticsearch правильный способ избежать пробелов, ? не работает во всех сценариях

Я пытаюсь заставить поиск с пробелами работать правильно в elasticsearch, но у меня много проблем с тем, чтобы заставить его вести себя так же, как и в другом поле.

У меня есть два поля, Name и Addresses.First().Line1, в которых я хочу иметь возможность искать и сохранять пробелы в поиске. Например, поиск Bob Smi* вернет Bob Smith, а не только Bob.

Это работает для моего поля имени, выполняя поиск строки запроса с заменой пробела на ?. Я также использую подстановочный знак, поэтому мой последний запрос — *bob?smi*.

Однако, когда я пытаюсь выполнить поиск по строке 1, я не получаю результатов. Например. *4800* возвращает запись со строкой 1, например 4800 Street, но когда я делаю то же преобразование с 4800 street, чтобы получить *4800?street*, я не получаю никаких результатов.

Ниже мой запрос

{
  "from": 0,
  "size": 50,
  "query": {
    "bool": {
      "must": [
        {
          "query_string": {
            "query": "*4800?Street*",
            "fields": [
              "name",
              "addresses.line1"
            ]
          }
        }
      ]
    }
  }
}

не возвращает никакого результата.

Почему *bob?smi* возвращает результат с именем Bob Smith, а *4800?street* не возвращает результат с позицией 4800 street?

Ниже показано, как оба поля настроены в индексе:

.Text(smd => smd.Name(c => c.Name).Analyzer(ElasticIndexCreator.SortAnalyzer).Fielddata())

.Nested<Address>(nomd => nomd.Name(p => p.PrimaryAddress).Properties(MapAddressProperties))

//from MapAddressProperties()

.Text(smd2 => smd2.Name(x => x.Line1).Analyzer(ElasticIndexCreator.SortAnalyzer).Fielddata())

Сопоставления в эластике:

"name": {
    "type": "text",
        "fields": {
            "keyword": {
                "type": "keyword",
                "ignore_above": 256
            }
        }
    }
}
"addresses": {
    "line1": {
        "type": "text",
        "fields": {
            "keyword": {
                "type": "keyword",
                "ignore_above": 256
            }
        }
    },
 }

Есть ли другой, лучший способ избежать пробела в строке запроса elasticsearch? Я также пробовал \\ и \\\\ (в С# оценивается как \\) вместо ? безрезультатно.


person DLeh    schedule 18.01.2018    source источник
comment
Рассматривали ли вы использование запроса на соответствие фразе или префиксу фразы соответствия? Кажется, это больше соответствует тому, что вы хотите, учитывая варианты использования, которые вы представили до сих пор: elastic.co/guide/en/elasticsearch/reference/current/   -  person Kevin Secrist    schedule 25.01.2018
comment
Кажется, это работает только для одного поля. У меня есть много полей, которые я просматриваю, это всего лишь пример двух из них.   -  person DLeh    schedule 25.01.2018
comment
Я прочитал ваш пост несколько раз, но я не уверен, что понимаю, что здесь требуется. Ищите с пробелами, но при этом пытаетесь с ?? Для справки, чтобы искать 4800 street именно так, как вы его видите, вам нужно использовать "query": "\"4800 street\"". Двойные кавычки, окружающие текст, чтобы он искался точно так же.   -  person Andrei Stefan    schedule 25.01.2018
comment
Что касается *bob?smi*, какой именно запрос и документ соответствуют? Потому что приведенные вами примеры - name из Bob Smith и поиск *bob?smi* НЕ вернут совпадение.   -  person Andrei Stefan    schedule 25.01.2018
comment
Ваш документ и query_string вернут что-то, если вы будете искать "query": "*Bob?Smi*" внутри name.keyword.   -  person Andrei Stefan    schedule 25.01.2018
comment
@AndreiStefan при поиске "\"4800 street\"" вернул результаты того же типа, некоторые для 4800 некоторые для street   -  person DLeh    schedule 25.01.2018
comment
@AndreiStefan, точный запрос и результат такие, как показано. Другой пример: поиск *abc?company* возвращает результат с именем ABC Company. ? предназначен для замены любого персонажа и, кажется, отлично работает для поля имени   -  person DLeh    schedule 25.01.2018
comment
Пожалуйста, предоставьте отдельный упрощенный пример (с полным сопоставлением, данными и запросом) в gist, демонстрирующий, что "\"4800 street\"" соответствует address.line1: street.   -  person Andrei Stefan    schedule 25.01.2018
comment
Я считаю, что мой пример довольно ясен. Я ищу два поля с одинаковым типом сопоставления. Я использую строку запроса, потому что у меня есть много полей, которые я ищу одновременно. Поиск в поле name дает правильные результаты, когда в запросе есть пробелы, а поиск в поле addresses.line1 — нет. Должна быть какая-то разница в том, как эти поля создаются или интерпретируются, но я не могу найти доказательств того, что такая разница существует.   -  person DLeh    schedule 25.01.2018
comment
И я говорю вам, что я проверил это с картой и документами, как я полагал, которые у вас есть. Я не могу воспроизвести ваши утверждения. Прости за это. Если вы не предоставите тест, который я просил, я не смогу вам помочь. Еще одна деталь: я протестировал это в консоли Dev Tools (что означает отсутствие кода C # нигде). Сначала нам нужно убрать вещи из обычного curl запроса, который получает кластер ES, а не то, что делает ваш код.   -  person Andrei Stefan    schedule 25.01.2018
comment
Единственная причина, которую я могу придумать, заключается в том, что это как-то связано с тем, что поле является вложенным. Если бы вы могли предоставить суть, запрошенную @AndreiStefan, я мог бы проверить это.   -  person slinzerthegod    schedule 31.01.2018
comment
@AndreiStefan и @slinzerthegod Я не уверен, какая еще информация вам нужна, я уже предоставил сопоставление и упрощенный запрос. Как мне получить gist, как вы упомянули?   -  person DLeh    schedule 31.01.2018
comment
@DLeh это суть: gist.github.com. В него вы можете добавить REST-команды, которые вы использовали для проверки этого. Он должен включать в себя создание индекса и его отображение, некоторые простые тестовые данные и некоторые запросы, которые показывают нам, что не работает, а что должно работать.   -  person Andrei Stefan    schedule 31.01.2018
comment
Вот начало, которое начинает иллюстрировать мою проблему. Я буду продолжать добавлять больше примеров с другими вещами, которые я пробовал. gist.github.com/DrLeh/4288c26a112479e400865d04f99723a1   -  person DLeh    schedule 07.02.2018


Ответы (2)


Попробуйте использовать addresses.line1.keyword (то есть попробуйте мультиполе keyword, которое вы определили для addresses.line1) в параметре fields a запрос с подстановочными знаками на уровне термина:

{
    "query": {
        "wildcard": {
            "addresses.line1.keyword": {
                "wildcard": "*4800 street*"
            }
        }
    }
}

Согласно документации Elasticsearch по полнотекстовый поиск с подстановочными знаками, если вы выполняете поиск по addresses.line1 (чей тип text, поэтому применяются правила полнотекстового поиска), поиск будет выполняться по каждому термину, проанализированному вне поля, то есть один раз по 4800 и снова против street, ни один из которых не соответствует вашему подстановочному знаку *4800?street*. Мультиполе addresses.line1.keyword содержит исходное значение 4800 street и должно соответствовать шаблону запроса с использованием запроса с подстановочными знаками на уровне термина.


Кстати, мелкая гнида: само определение типа отображения кажется неполным для поля addresses. Вы сказали, что это:

"addresses": {
    "line1": {
        "type": "text",
        "fields": {
            "keyword": {
                "type": "keyword",
                "ignore_above": 256
            }
        }
    },
}

Но ИМХО вместо этого должно быть:

"addresses": {
    "properties": {
        "line1": {
            "type": "text",
            "fields": {
                "keyword": {
                    "type": "keyword",
                    "ignore_above": 256
                }
            }
        },
    }
}
person astralblue    schedule 26.01.2018

Наконец-то нашел правильную настройку после тонн экспериментов. Конфигурация, которая работала для меня, была следующей:

  1. Использовать текст с полевыми данными в столбцах
  2. Выполните поиск с помощью QueryString с подстановочными знаками, заменив пробелы на ?, например. Введено bob smith, эластичный запрос с *bob?smith*
  3. Используйте вложенные запросы для дочерних объектов. Как ни странно, addresses.line1 будет возвращать данные при поиске, скажем, 4800, но не при попытке выполнить *4800?street*. Использование вложенного запроса позволяет этому функционировать должным образом.

Из того, что я слышал, использование полевых данных очень интенсивно использует память, а использование подстановочных знаков требует очень много времени, так что это, вероятно, не оптимальное решение, но это единственное, что я нашел. Если есть другой лучший способ сделать это, пожалуйста, просветите меня.

Примеры запросов на C# с использованием Nest:

var query = Query<Student>.QueryString(qs => qs
                .Fields(f => f
                .Field(c => c.Name)
                //.Field(c => c.PrimaryAddress.Line1) //this doesn't work
                )
                .Query(testCase.Term)
            );

query |= Query<Student>.Nested(n => n
        .Path(p => p.Addresses)
            .Query(q => q
                .QueryString(qs => qs
                        .Fields(f => f.Field(c => c.Addresses.First().Line1))
                        .Query(testCase.Term)
                    )
            )
        );

Пример сопоставления:

.Map<Student>(s => s.Properties(p => p
    .Text(t => t.Name(z => z.Name).Fielddata())
    .Nested<StudentAddress>(n => n
        .Name(ap => ap.Addresses)
        .Properties(ap => ap.Text(t => t.Name(z => z.Line1).Fielddata())
    )
))
person DLeh    schedule 14.02.2018