返回

ElasticSearch 笔记

目录

js版

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import { Client } from '@elastic/elasticsearch';

const esClient = new Client({
  node: 'http://localhost:9200',
  auth: {
    username: 'elastic',
    password: '...',
  }
});

async function ensureIndexExist() {
  const indexName = 'documents';

  const exist = await esClient.indices.exists({ index: indexName });

  if (!exist) {
    await esClient.indices.create({
      index: indexName,
      body: {
        mappings: {
          properties: {
            title: { type: 'text' },
            content: { type: 'text' },
            createAt: { type: 'date' },
          }
        }
      }
    });
  }
}

// 初始化索引
await ensureIndexExist().catch(console.error);

app.post('/doc', async (req, res) => {
  try {
    const { title, content } = req.body;

    if (!title || !content) {
      return res.status(400).json({ error: "title and content required" });
    }

    const doc = {
      title,
      content,
      createAt: new Date().toISOString()
    };

    const result = await esClient.index({
      index: 'documents',
      document: doc,
      refresh: true
    });

    res.status(201).json({
      status: 'accept',
      id: result._id
    });
  } catch (error) {
    console.error('Indexing error:', error);
    res.status(500).json({ status: 'reject' });
  }
});

app.get('/search', async (req, res) => {
  try {
    const { q } = req.query;

    if (!q) {
      return res.status(400).json({ error: 'Query parameter "q" is required' });
    }

    const result = await esClient.search({
      index: 'documents',
      body: {
        query: {
          multi_match: {
            query: q,
            fields: ['title', 'content']
          }
        }
      }
    });

    const hits = result.hits.hits.map(hit => ({
      id: hit._id,
      ...hit._source
    }));

    res.json({
      total: result.hits.total.value,
      results: hits
    });
  } catch (error) {
    console.error('Search error:', error);
    res.status(500).json({ status: 'reject' });
  }
});

安装ik 分词器

bin/elasticsearch-plugin install https://get.infini.cloud/elasticsearch/analysis-ik/${ES_VERSION}

ik_smart:最少切分

ik_max_word:最细切分

usage

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
async function ensureIndexExist() {
  const indexName = 'documents';
  try {
    await esClient.indices.delete({ index: indexName });
    console.log('旧索引已删除');
  } catch (e) {
    if (e.meta?.statusCode !== 404) {
      console.error('删除索引失败:', e);
    }
  }
  await esClient.indices.create({
    index: indexName,
    body: {
      mappings: {
        properties: {
          title: {
            type: 'text',
            analyzer: 'ik_max_word',
            search_analyzer: 'ik_smart'
          },
          content: {
            type: 'text',
            analyzer: 'ik_max_word',
            search_analyzer: 'ik_smart'
          },
          createAt: { type: 'date' }
        }
      }
    }
  });
}

app.post('/test-docs', async (req, res) => {
  const testDocs = [
    { title: '苹果手机发布', content: '苹果公司发布了最新款iPhone手机,搭载A17芯片。' },
    { title: '华为鸿蒙系统', content: '华为推出了自研的鸿蒙操作系统,支持多设备协同。' },
    { title: '人工智能助手', content: '通义千问是阿里巴巴推出的AI大语言模型助手。' },
    { title: '新能源汽车', content: '比亚迪和特斯拉是新能源汽车领域的领先企业。' }
  ];

  try {
    const results = [];
    for (const doc of testDocs) {
      const result = await esClient.index({
        index: 'documents',
        document: {
          ...doc,
          createAt: new Date().toISOString()
        },
        refresh: true
      });
      results.push({ id: result._id, title: doc.title });
    }

    res.json({
      status: 'success',
      inserted: results.length,
      docs: results
    });
  } catch (error) {
    console.error('插入测试文档失败:', error);
    res.status(500).json({ error: '插入失败' });
  }
});
Licensed under CC BY-NC-SA 4.0