Полнотекстовый поиск с Couchbase и Go

19 minute read

Перевод статьи "Using Full Text Search (FTS) with Couchbase in a GoLang Application"

Недавно я написал статью о использовании полнотекстового поиска (Full Text Search) в приложениях на Node.js, в которой говорилось о использовании для реализации поиска Couchbase Server 4.5 и выше. Возможно вы уже знаете, что в Couchbase Server 4.5 появился полнотекстовый поиск(пока еще превью для разработчиков). За это отдельное спасибо ребятам из Couchbase, которые стараются быть открытыми, насколько это возможно. Теперь, вместо не очень производительных запросов по шаблону, можно использовать запросы по полнотекстовому индексу. Таким образом, необходимость использовать ElasticSearch или Solr становится не такой острой, конечно, если ваш бизнес не строится исключительно вокруг поиска.

Мы будем использовать пример из прошлой статьи, написанные на Node.js и постараемся переписать его на Go. Не переживайте, даже если вы не работали с Node.js, пример всеравно достаточно простой и понятный. В прошлой статье мы представили себе некоторый условный сценарий ранжирования резюме, в котором мы сканировали резюме соискателей по некоторым ключевым словам и давали им оценку. Продолжим двигаться в этом же направлении.

Создаем новый проект

Чтобы полностью разобраться в нашем примере, мы начнем с самого начала. Для работы нам понадобится установленный Go, а также сконфигурированный и запущенный Couchbase Server 4.5

Создаем новый проект. В моем случае проект будет находится в $GOPATH/src/github.com/nraboy/cbfts/main.go. Перед тем как окунуться в программирование, необходимо установить Couchbase Go SDK.

go get github.com/couchbase/gocb

Почти все готово и мы уже вот-вот начнем писать код. Но нам еще нужно настроить необходимые индексы в Couchbase.

Добавляем индекс для полнотекстового поиска

Перед тем как начать пользоваться полнотекстовым поиском, необходимо создать специальный индекс. Это можно легко сделать с помощью административного интерфейса. Необходимо выбрать Indexes -> Full Text таб

В этой секции можно кликнуть на "New Full Text Index" и выбрать бакет, к которому должен примениться этот индекс. Для нашего примера мы будем использовать бакет по умолчанию, а индекс будет называться "resume-search". Индекс в нашем примере имеет базовые настройки, если вам нужно больше подробностей, то можете найти их в документации.

После создания индекса, нажмите кнопку обновления. Теперь можно проверить работу индекса через все тот же дашборд.

Модель данных

Теперь окинем взглядом наду модель данных. Каждый документ представляет собой резюме соискателя. Если проявить немного фантазии, то можно представить что наши данные выглядят как-то так:

{
    "firstname": "Nic",
    "lastname": "Raboy",
    "skills": [
        "java",
        "node.js",
        "golang",
        "nosql"
    ],
    "summary": "I am a cool guy working on cool things",
    "social": {
        "github": "https://www.github.com/nraboy",
        "twitter": "https://www.twitter.com/nraboy"
    },
    "employment": [
        {
            "employer": "Couchbase",
            "title": "Developer Advocate",
            "location": "San Francisco"
        }
    ]
}

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

Самое важное, на что нам нужно обратить внимание, это текст "Developer Advocate". Мы напишем Go приложение, которое будет выполнять поиск именно по этой фразе.

Разработка приложения

Так как наше приложение очень маленькое, то весь код поместиться в одном единственном файле main.go. Начнем с импортирования всех необходимых зависимостей:

package main

import (
    "encoding/json"
    "fmt"

    "github.com/couchbase/gocb"
    "github.com/couchbase/gocb/cbft"
)

Обратите внимание, что мы импортировали пакет для работы с JSON. Также, нам понадобятся пакеты для работы с Couchbase и Couchbase FTS.

Данные, которые мы будем собирать, весьма специфичны. Поэтому стоит создать еще одну структуру данных. Назовем эту структуру FtsHit и выглядеть она будет вот так:

type FtsHit struct {
    ID    string  `json:"id,omitempty"`
    Score float64 `json:"score,omitempty"`
}

Мы будем сохранять каждый id и оценку всех документов которые мы получили через поиск. Каждое поле структуры имеет свой специальный JSON тег, которое говорит, что поле нужно игнорировать если оно пустое.

Теперь напишем немного магического кода в main функции:

func main() {
    cluster, _ := gocb.Connect("couchbase://localhost")
    bucket, _ := cluster.OpenBucket("default", "")
    query := gocb.NewSearchQuery("resume-search",
            cbft.NewMatchQuery("developer advocate"))

    result, _ := bucket.ExecuteSearchQuery(query)

    var ftsHit *FtsHit
    for _, hit := range result.Hits() {
        ftsHit = &FtsHit{ID: hit.Id, Score: hit.Score}
        jsonHit, _ := json.Marshal(&ftsHit)
        fmt.Println(string(jsonHit))
    }
}

Перед тем как выполнять поиск, нам нужно установить соединение с Couchbase и открыть бакет. В нашем примере используется локальная нода и бакет по умолчанию. После подключения к базе, мы можем запускать поисковые запросы по ранее созданному индексу "resume-search". Этот запрос ищет текст "developer advocate" во всех документах и во всех полях документа. Если искомый текст будет найден в любом месте документа, то мы засчитываем хит(hit).

После того как выполниться запрос, мы выполним итерацию по всем результатам и, с помощью пакета для работы с JSON, распарсим каждый в структуру FtsHit.

Пока все хорошо, не так ли?

Представим, что теперь вам нужен чуть более специфический поиск. Конечно, хорошо иметь возможность искать по всему документу, но мы хотим искать только по списку прошлых мест работы соискателя.

Для этого нам достаточно немного уточнить наш SearchQuery:

query := gocb.NewSearchQuery("resume-search", 
    cbft.NewMatchQuery("developer advocate").Field("employment.title"))

Пожалуй оставим этот пример простым, хотя есть еще тысяча замечательных вещей, которые нам дает полнотекстовый поиск. Вы можете сделать ваш запрос более специфичным или добавить больше уточнений в ваш запрос. Больше сведений о полнотекстовом поиске можно почерпнуть из документации.

Заключение

Мы рассмотрели как можно быстро начать использовать полнотекстовый поиск Couchbase в приложениях на Go. Полнотекстовый поиск позволяет находить документы быстрее чем использование кучи различных масок.

comments powered by Disqus