【问题标题】:NodeJs connecting to elasticsearchNodeJs 连接到 elasticsearch
【发布时间】:2019-02-20 14:14:32
【问题描述】:

我正在尝试更新我的 REST API 以使用 elasticsearch,我发现 mongoosastic 插件似乎是最好的解决方案,但我不知道如何将 elasticsearch 与节点服务器连接。

根据 mongoosastic 文档 (https://github.com/mongoosastic/mongoosastic),user.model.ts 中的代码应该可以工作,但是当我创建用户然后点击 http://localhost:9200/user/user/_search 时,正文是以下 json:

{
    "error": {
        "root_cause": [{
            "type": "index_not_found_exception",
            "reason": "no such index",
            "resource.type": "index_or_alias",
            "resource.id": "user",
            "index_uuid": "_na_",
            "index": "user"
        }],
        "type": "index_not_found_exception",
        "reason": "no such index",
        "resource.type": "index_or_alias",
        "resource.id": "user",
        "index_uuid": "_na_",
        "index": "user"
    },
    "status": 404
}

创建新用户时,控制台出现以下错误:

POST http://0.0.0.0:9200/users/user/5b9e535a6a2a4100cb86e9a3?refresh=true => connect ECONNREFUSED 0.0.0.0:9200
    at Log.error (/app/node_modules/elasticsearch/src/lib/log.js:226:56)
    at checkRespForFailure (/app/node_modules/elasticsearch/src/lib/transport.js:259:18)
    at HttpConnector.<anonymous> (/app/node_modules/elasticsearch/src/lib/connectors/http.js:163:7)
    at ClientRequest.wrapper (/app/node_modules/elasticsearch/node_modules/lodash/lodash.js:4949:19)
    at ClientRequest.emit (events.js:182:13)
    at Socket.socketErrorListener (_http_client.js:391:9)
    at Socket.emit (events.js:182:13)
    at emitErrorNT (internal/streams/destroy.js:82:8)
    at emitErrorAndCloseNT (internal/streams/destroy.js:50:3)
    at process._tickCallback (internal/process/next_tick.js:63:19)
::ffff:172.18.0.1 - - [16/Sep/2018:12:58:02 +0000] "POST /api/v0/user/ HTTP/1.1" 201 230 "http://localhost:9000/doc/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36"
Elasticsearch WARNING: 2018-09-16T12:58:02Z
  Unable to revive connection: http://0.0.0.0:9200/
Elasticsearch WARNING: 2018-09-16T12:58:02Z
  No living connections

所以我认为错误只是我配置错误的一些配置选项,但我无法找出我做错了什么。

通过浏览器转到http://localhost:9200/_cluster/health 给我:

{
    "cluster_name": "docker-cluster",
    "status": "yellow",
    "timed_out": false,
    "number_of_nodes": 1,
    "number_of_data_nodes": 1,
    "active_primary_shards": 1,
    "active_shards": 1,
    "relocating_shards": 0,
    "initializing_shards": 0,
    "unassigned_shards": 1,
    "delayed_unassigned_shards": 0,
    "number_of_pending_tasks": 0,
    "number_of_in_flight_fetch": 0,
    "task_max_waiting_in_queue_millis": 0,
    "active_shards_percent_as_number": 50.0
}

我也使用 docker。

Docker 文件:

FROM mhart/alpine-node:10
ADD . /app
WORKDIR /app
RUN apk --no-cache add --virtual builds-deps build-base python &&\
    yarn global add nodemon &&\
    yarn &&\
    apk del builds-deps build-base python

docker-compose.yml:

version: "3.3"
services:
  api:

    build: .
    links:
      - 'mongo:mongo'
      - 'elasticsearch:elasticsearch'
    env_file:
      - .env
    volumes:
      - .:/app
      - /app/node_modules
    ports:
      - "0.0.0.0:9000:9000"
    command: sh -c "mkdir -p dist && touch ./dist/app.js && yarn run start"

  transpiler:
    build: .
    volumes:
      - .:/app
      - /app/node_modules
    command: yarn run transpile -- -w

  linter:
    build: .
    volumes:
      - .:/app
      - /app/node_modules
    command: nodemon --delay 500ms --exec yarn run lint

  mongo:
    image: mongo:4.0
    ports:
      - "27017"
    command: mongod
    volumes:
      - ./data:/data/db

  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:6.1.1
    volumes:
      - ./esdata:/esdata
    environment:
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
      - discovery.type=single-node
    ports:
      - "9300:9300"
      - "9200:9200"

  mocha:
    build: .
    volumes:
      - .:/app
      - /app/node_modules
    links:
      - 'mongo:mongo'
    command: nodemon --delay 500ms --exec yarn run test
    env_file:
      - .env
    environment:
      NODE_ENV: 'test'

user.model.ts

import * as mongoose from 'mongoose'
import * as mongoosastic from 'mongoosastic'
import * as elasticsearch from 'elasticsearch'
import * as bcrypt from 'bcrypt'
import * as emailValidator from 'email-validator'
import { IImage, Image } from '../image/image.model'
import config from '../../config/environment'
import { NextFunction } from 'express'
import * as beautifyUnique from 'mongoose-beautiful-unique-validation'

const SALT_WORK_FACTOR: number = config.bcryptWorkFactor

export interface IUser extends mongoose.Document {
    mail: string
    password: string
    login: string
    profilPic: mongoose.Types.ObjectId
    public: {
        mail: string
        profilPic: mongoose.Types.ObjectId
        login: string
    }
}

const UserSchema: mongoose.Schema = new mongoose.Schema({
    login: {
        required: true,
        type: String,
        unique: 'Le nom d\'utilisateur `{VALUE}` est déjà utilisé'
    },
    mail: {
        required: true,
        type: String,
        unique: 'Le mail `{VALUE}` est déjà utilisé'
    },
    password: { required: true, type: String, select: false },
    profilPic: { type: mongoose.Schema.Types.ObjectId, ref: 'Image' },
}, { timestamps: true })

UserSchema.virtual('public').get(function (): object {
    return {
        id: this.id,
        mail: this.mail,
        profilPic: this.profilPic,
        login: this.login,
    }
})

UserSchema.pre<IUser>('save', function (next: NextFunction): void {
    // If user already have a picture no need to set the default one
    if (this.profilPic) {
        return next()
    }
    const imgProfil: IImage = new Image({
        name: 'default.png',
        link: config.assetsURI + 'user/profil/default.png',
        type: 'png',
        width: 502,
        height: 502,
    })
    Image.create(imgProfil).then((img: IImage) => {
        this.profilPic = img.id
        return next()
    }).catch((error: Error) => {
        return next(error)
    })
})

UserSchema.method('comparePassword',
    (password: string, hash: string): Promise<boolean> => {
        return bcrypt.compare(password, hash)
            .then((value: boolean) => {
                return value
            })
    })

UserSchema.method('hashPassword',
    (password: string): Promise<string> => {
        return bcrypt.hash(password, SALT_WORK_FACTOR)
            .then((hashedPassword: string) => {
                return hashedPassword
            })
    })

UserSchema.static('validEmail', (email: string): boolean => {
    return emailValidator.validate(email)
})

UserSchema.set('toJSON', {
    transform: (doc: IUser, ret: IUser): void => {
        ret.id = ret._id
        delete ret._id
        delete ret.__v
    }
})

UserSchema.plugin(beautifyUnique)
const esClient: elasticsearch.Client = new elasticsearch.Client({
    host: '0.0.0.0:9200'
})
UserSchema.plugin(mongoosastic, {
    esClient: esClient
})
export const User: mongoose.Model<IUser> =
    mongoose.model<IUser>('User', UserSchema)

【问题讨论】:

  • 嗯...也许试试 localhost:9200 而不是 0.0.0.0:9200?
  • 我在 0.0.0.0:9200 之前尝试了 localhost:9200 和 127.0.0.1:9200 但我总是收到来自 elasticsearch 的 ECONNREFUSED 消息
  • 您的 nodejs 应用程序是否在容器中运行?如果是这样,请在容器内尝试 curl localhost:9200。我怀疑这会失败。如果是这样,请尝试卷曲 host.docker.internal:9200。这可能行得通。
  • 是的,一切都在容器中运行。命令curl localhost:9200 给我一个有效的json,curl host.docker.internal:9200curl: (6) Could not resolve host: host.docker.internal

标签: node.js docker elasticsearch mongoose


【解决方案1】:

您应该将此设置为可配置的,并使用 Docker 内部的 DNS 在主机之间进行通信。

在您的 JavaScript 代码中,最直接的做法是使用环境变量

const esClient: elasticsearch.Client = new elasticsearch.Client({
    host: process.env.ELASTICSEARCH_HOST
})

当您开发代码时(在本地,在 Docker 之外),您可以建立一个测试 Elasticsearch(如果您愿意,可以在容器中)并设置 ELASTICSEARCH_HOST=localhost:9200。当你去部署它时,你可以在你的docker-compose.yml中设置环境变量:

services:
  elasticsearch: 
    image: docker.elastic.co/elasticsearch/elasticsearch:6.1.1
    et: cetera
  api:
    build: .
    environment:
      ELASTICSEARCH_HOST: 'elasticsearch:9200'
    env_file:
      - .env
    ports:
      - "0.0.0.0:9000:9000"

(您不再需要links:;它没有害处,但它是不必要的冗长。我会使用Dockerfile 在映像中安装您的应用程序代码并设置默认命令。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-07
    • 2021-09-15
    • 2016-11-22
    • 2017-10-04
    • 2019-10-08
    • 1970-01-01
    • 2016-01-29
    • 1970-01-01
    相关资源
    最近更新 更多