Elastic
Jina AI
모델
API
keyboard_arrow_down
Reader
어떤 URL이든 Markdown으로 변환하여 LLM 그라운딩을 개선하세요.
Embeddings
멀티모달 및 다국어 임베딩.
Reranker
검색 관련성을 극대화하는 리랭커.
MCP
terminal
CLI
article
llms.txt
smart_toy
에이전트
data_object
스키마
menu_book
문서
로그인
login
Jira 지원 티켓 검색하기
Jina Embeddings와 Reranker의 장점
기술 블로그
4월 10, 2024

Jina Reranker와 Haystack 2.0을 활용한 Jira 티켓 검색

Jina Reranker와 Embeddings를 Haystack과 함께 사용하여 자체 Jira 티켓 검색 엔진을 만드는 방법을 알아보세요. 이를 통해 운영을 간소화하고 중복된 이슈를 만드는 데 시간을 낭비하지 않을 수 있습니다.
Graphic with "Reranker" and "Haystack by deepset" on a black background with teal decorative elements.
Francesco Kruk • 10 분 소요

Deepset의 Haystack 2.0에 Jina Embeddings가 통합되고 Jina Reranker가 출시된 데 이어, Jina Reranker가 이제 Jina Haystack 확장을 통해서도 사용 가능하게 되었음을 기쁘게 발표합니다.

Jina AI | Haystack
최신 Jina AI 임베딩 모델 사용하기
HaystackAuthors deepset
Reranker API
손쉽게 검색 연관성과 RAG 정확도 극대화하기

Haystack은 GenAI 프로젝트 수명 주기의 모든 단계를 지원하는 종단간 프레임워크입니다. 문서 검색, 검색 증강 생성(RAG), 질문 답변 또는 답변 생성을 수행하고자 할 때, Haystack은 최신 임베딩 모델과 LLM을 파이프라인으로 구성하여 종단간 NLP 애플리케이션을 구축하고 사용 사례를 해결할 수 있습니다.

Haystack | Haystack
구성 가능한 오픈소스 AI 프레임워크 Haystack
Haystack

이 글에서는 이들을 사용하여 자체 Jira 티켓 검색 엔진을 만들어 운영을 효율화하고 중복 이슈 생성으로 시간을 낭비하지 않는 방법을 보여드리겠습니다.

이 튜토리얼을 따라하려면 Jina Reranker API 키가 필요합니다. Jina Reranker 웹사이트에서 100만 토큰의 무료 체험판 할당량으로 API 키를 만들 수 있습니다.

💡
Colab에서 따라하거나 노트북을 다운로드하여 진행할 수 있습니다.

tagJira 지원 티켓 검색하기

복잡한 프로젝트를 다루는 모든 팀은 이슈를 등록하고 싶은데 해당 문제에 대한 티켓이 이미 존재하는지 알 수 없어 답답했던 경험이 있을 것입니다.

다음 튜토리얼에서는 Jina Reranker와 Haystack 파이프라인을 사용하여 새로 생성되는 티켓에 대해 가능한 중복 티켓을 제안하는 도구를 직접 만드는 방법을 보여드리겠습니다.

  • 기존 모든 티켓과 대조해야 하는 티켓을 입력하면, 파이프라인이 먼저 데이터베이스에서 모든 관련 이슈를 검색합니다.
  • 그런 다음 원본 티켓(데이터베이스에 이미 존재하는 경우)과 모든 하위 티켓(원본 티켓의 상위 ID에 해당하는 티켓)을 목록에서 제거합니다.
  • 최종 선택은 이제 원본 티켓과 동일한 주제를 다룰 수 있지만 데이터베이스에서 ID를 통해 그렇게 표시되지 않은 이슈들만 포함합니다. 이러한 티켓들은 최대 연관성을 보장하기 위해 재순위가 매겨지며 데이터베이스의 중복 항목을 식별할 수 있게 합니다.

tag데이터셋 가져오기

우리의 솔루션을 구현하기 위해 Apache Zookeeper 프로젝트의 모든 "진행 중" 상태인 Jira 티켓을 선택했습니다. 이것은 분산 애플리케이션의 프로세스를 조정하기 위한 오픈소스 서비스입니다.

더 편리하게 사용할 수 있도록 티켓들을 JSON 파일에 저장했습니다. 파일을 작업 공간에 다운로드하세요.

tag사전 요구사항 설정

요구사항을 설치하려면 다음을 실행하세요:

pip install --q chromadb haystack-ai jina-haystack chroma-haystack

API 키를 입력하려면 환경 변수로 설정하세요:

import os
import getpass

os.environ["JINA_API_KEY"] = getpass.getpass()
💡
노트북을 통해 이 코드를 실행하는 경우, getpass.getpass()는 해당 코드 블록 아래에 API 키를 입력하라는 메시지를 표시합니다. 거기에 키를 입력하고 enter를 눌러 튜토리얼을 계속할 수 있습니다. 원하는 경우 getpass.getpass()를 API 키 자체로 대체할 수도 있습니다.

tag인덱싱 파이프라인 구축

인덱싱 파이프라인은 티켓을 전처리하고, 벡터로 변환한 후 저장합니다. 벡터 임베딩을 저장하기 위해 Chroma Document Store Haystack 통합을 통해 Chroma DocumentStore를 벡터 데이터베이스로 사용할 것입니다.

from haystack_integrations.document_stores.chroma import ChromaDocumentStore

document_store = ChromaDocumentStore()

먼저 관련 문서 필드만 고려하고 모든 빈 항목을 삭제하는 사용자 정의 데이터 전처리기를 정의하겠습니다:

import json
from typing import List
from haystack import Document, component

relevant_keys = ['Summary', 'Issue key', 'Issue id', 'Parent id', 'Issue type', 'Status', 'Project lead', 'Priority', 'Assignee', 'Reporter', 'Creator', 'Created', 'Updated', 'Last Viewed', 'Due Date', 'Labels',
                 'Description', 'Comment', 'Comment__1', 'Comment__2', 'Comment__3', 'Comment__4', 'Comment__5', 'Comment__6', 'Comment__7', 'Comment__8', 'Comment__9', 'Comment__10', 'Comment__11', 'Comment__12',
                 'Comment__13', 'Comment__14', 'Comment__15']

@component
class RemoveKeys:
    @component.output_types(documents=List[Document])
    def run(self, file_name: str):
        with open(file_name, 'r') as file:
            tickets = json.load(file)
        cleaned_tickets = []
        for t in tickets:
            t = {k: v for k, v in t.items() if k in relevant_keys and v}
            cleaned_tickets.append(t)
        return {'documents': cleaned_tickets}

그런 다음 티켓을 Haystack이 이해할 수 있는 Document 객체로 변환하기 위한 사용자 정의 JSON 변환기를 만들어야 합니다:

@component
class JsonConverter:
    @component.output_types(documents=List[Document])
    def run(self, tickets: List[Document]):
        tickets_documents = []
        for t in tickets:
            if 'Parent id' in t:
                t = Document(content=json.dumps(t), meta={'Issue key': t['Issue key'], 'Issue id': t['Issue id'], 'Parent id': t['Parent id']})
            else:
                t = Document(content=json.dumps(t), meta={'Issue key': t['Issue key'], 'Issue id': t['Issue id'], 'Parent id': ''})
            tickets_documents.append(t)
        return {'documents': tickets_documents}

마지막으로 Documents를 임베딩하고 이러한 임베딩을 ChromaDocumentStore에 작성합니다:

from haystack import Pipeline

from haystack.components.writers import DocumentWriter
from haystack_integrations.components.retrievers.chroma import ChromaEmbeddingRetriever
from haystack.document_stores.types import DuplicatePolicy

from haystack_integrations.components.embedders.jina import JinaDocumentEmbedder

retriever = ChromaEmbeddingRetriever(document_store=document_store)
retriever_reranker = ChromaEmbeddingRetriever(document_store=document_store)

indexing_pipeline = Pipeline()
indexing_pipeline.add_component('cleaner', RemoveKeys())
indexing_pipeline.add_component('converter', JsonConverter())
indexing_pipeline.add_component('embedder', JinaDocumentEmbedder(model='jina-embeddings-v2-base-en'))
indexing_pipeline.add_component('writer', DocumentWriter(document_store=document_store, policy=DuplicatePolicy.SKIP))

indexing_pipeline.connect('cleaner', 'converter')
indexing_pipeline.connect('converter', 'embedder')
indexing_pipeline.connect('embedder', 'writer')

indexing_pipeline.run({'cleaner': {'file_name': 'tickets.json'}})

이렇게 하면 진행 상태 표시줄이 생성되고 저장된 내용에 대한 간단한 JSON 정보가 출력됩니다:

Calculating embeddings: 100%|██████████| 1/1 [00:01<00:00,  1.21s/it]
{'embedder': {'meta': {'model': 'jina-embeddings-v2-base-en',
   'usage': {'total_tokens': 20067, 'prompt_tokens': 20067}}},
 'writer': {'documents_written': 31}}

tag쿼리 파이프라인 구축하기

티켓을 비교할 수 있도록 쿼리 파이프라인을 만들어보겠습니다. Haystack 2.0에서 Retriever는 DocumentStore와 밀접하게 연결되어 있습니다. 이전에 초기화한 Retriever에 document store를 전달하면, 이 파이프라인은 우리가 생성한 문서에 접근하고 이를 reranker에 전달할 수 있습니다. 그러면 reranker는 이러한 문서들을 질문과 직접 비교하여 관련성에 따라 순위를 매깁니다.

먼저 쿼리로 전달된 이슈와 동일한 이슈 ID 또는 상위 ID를 포함하는 티켓을 제거하는 사용자 정의 클리너를 정의합니다:

from typing import Optional

@component
class RemoveRelated:
    @component.output_types(documents=List[Document])
    def run(self, tickets: List[Document], query_id: Optional[str]):
        retrieved_tickets = []
        for t in tickets:
            if not t.meta['Issue id'] == query_id and not t.meta['Parent id'] == query_id:
                retrieved_tickets.append(t)
        return {'documents': retrieved_tickets}

그런 다음 쿼리를 임베딩하고, 관련 문서를 검색하고, 선택 항목을 정리한 후 마지막으로 재순위를 매깁니다:

from haystack_integrations.components.embedders.jina import JinaTextEmbedder
from haystack_integrations.components.rankers.jina import JinaRanker

query_pipeline_reranker = Pipeline()
query_pipeline_reranker.add_component('query_embedder_reranker', JinaTextEmbedder(model='jina-embeddings-v2-base-en'))
query_pipeline_reranker.add_component('query_retriever_reranker', retriever_reranker)
query_pipeline_reranker.add_component('query_cleaner_reranker', RemoveRelated())
query_pipeline_reranker.add_component('query_ranker_reranker', JinaRanker())

query_pipeline_reranker.connect('query_embedder_reranker.embedding', 'query_retriever_reranker.query_embedding')
query_pipeline_reranker.connect('query_retriever_reranker', 'query_cleaner_reranker')
query_pipeline_reranker.connect('query_cleaner_reranker', 'query_ranker_reranker')
'text', 'query_embedder_reranker', 'meta'와 같은 기능이 포함된 쿼리 처리 워크플로우를 설명하는 순서도 다이어그램.

reranker로 인한 차이를 강조하기 위해, 최종 재순위 지정 단계가 없는 동일한 파이프라인을 분석했습니다(가독성을 위해 해당 코드는 이 게시물에서 생략되었지만 노트북에서 찾을 수 있습니다):

'query_embedding', 'query_retriever', 'query_cleaner' 컴포넌트가 있는 텍스트 검색 프로세스를 자세히 설명하는 순서도.

이 두 파이프라인의 결과를 비교하기 위해, 이제 기존 티켓의 형태로 쿼리를 정의합니다. 여기서는 "ZOOKEEPER-3282"입니다:

query_ticket_key = 'ZOOKEEPER-3282'

with open('tickets.json', 'r') as file:
    tickets = json.load(file)

for ticket in tickets:
    if ticket['Issue key'] == query_ticket_key:
        query = str(ticket)
        query_ticket_id = ticket['Issue id']

이것은 "documetations에 대한 대규모 리팩토링"에 관한 것입니다 [sic]. 맞춤법 오류에도 불구하고 Jina Reranker가 유사한 티켓을 정확하게 검색할 것을 보게 될 것입니다.

{
    "Summary": "a big refactor for the documetations"
    "Issue key": "ZOOKEEPER-3282"
    "Issue id:: 13216608
    "Parent id": ""
    "Issue Type": "Task"
    "Status": "In Progress"
    "Project lead": "phunt"
    "Priority": "Major"
    "Assignee": "maoling"
    "Reporter": "maoling"
    "Creator": "maoling"
    "Created": "19/Feb/19 11:50"
    "Updated": "04/Aug/19 12:48"
    "Last Viewed": "12/Mar/24 11:56"
    "Description": "Hi guys: I'am working on doing a big refactor for the documetations.it aims to - 1.make a better reading experiences and help users know more about zookeeper quickly,as good as other projects' doc(e.g redis,hbase). - 2.have less changes to diff with the original docs as far as possible. - 3.solve the problem when we have some new features or improvements,but cannot find a good place to doc it.   The new catalog may looks kile this: * is new one added. ** is the one to keep unchanged as far as possible. *** is the one modified. -------------------------------------------------------------- |---Overview    |---Welcome ** [1.1]    |---Overview ** [1.2]    |---Getting Started ** [1.3]    |---Release Notes ** [1.4] |---Developer    |---API *** [2.1]    |---Programmer's Guide ** [2.2]    |---Recipes *** [2.3]    |---Clients * [2.4]    |---Use Cases * [2.5] |---Admin & Ops    |---Administrator's Guide ** [3.1]    |---Quota Guide ** [3.2]    |---JMX ** [3.3]    |---Observers Guide ** [3.4]    |---Dynamic Reconfiguration ** [3.5]    |---Zookeeper CLI * [3.6]    |---Shell * [3.7]    |---Configuration flags * [3.8]    |---Troubleshooting & Tuning  * [3.9] |---Contributor Guidelines    |---General Guidelines * [4.1]    |---ZooKeeper Internals ** [4.2] |---Miscellaneous    |---Wiki ** [5.1]    |---Mailing Lists ** [5.2] -------------------------------------------------------------- The Roadmap is: 1.(I pick up it : D)  1.1 write API[2.1], which includes the:    1.1.1  original API Docs which is a Auto-generated java doc,just give a link.    1.1.2. Restful-api (the apis under the /zookeeper-contrib-rest/src/main/java/org/apache/zookeeper/server/jersey/resources)  1.2 write Clients[2.4], which includes the:      1.2.1 C client      1.2.2 zk-python, kazoo      1.2.3 Curator etc.......      look at an example from: https://redis.io/clients # write Recipes[2.3], which includes the:  - integrate "Java Example" and "Barrier and Queue Tutorial"(Since some bugs in the examples and they are obsolete,we may delete something) into it.  - suggest users to use the recipes implements of Curator and link to the Curator's recipes doc.   # write Zookeeper CLI[3.6], which includes the:  - about how to use the zk command line interface [./zkCli.sh]    e.g ls /; get ; rmr;create -e -p etc.......  - look at an example from redis: https://redis.io/topics/rediscli   # write shell[3.7], which includes the:   - list all usages of the shells under the zookeeper/bin. (e.g zkTxnLogToolkit.sh,zkCleanup.sh)   # write Configuration flags[3.8], which includes the:   - list all usages of configurations properties(e.g zookeeper.snapCount):   - move the original Advanced Configuration part of zookeeperAdmin.md into it.     look at an example from:https://coreos.com/etcd/docs/latest/op-guide/configuration.html    # write Troubleshooting & Tuning[3.9], which includes the:   - move the original "Gotchas: Common Problems and Troubleshooting" part of Administrator's Guide.md into it.   - move the original "FAQ" into into it.   - add some new contents (e.g https://www.yumpu.com/en/document/read/29574266/building-an-impenetrable-zookeeper-pdf-github).   look at an example from:https://redis.io/topics/problems                             https://coreos.com/etcd/docs/latest/tuning.html   # write General Guidelines[4.1], which includes the:  - move the original "Logging" part of ZooKeeper Internals into it as the logger specification.  - write specifications about code, git commit messages,github PR  etc ...    look at an example from:    http://hbase.apache.org/book.html#hbase.commit.msg.format   # write Use Cases[2.5], which includes the:  - just move the context from: https://cwiki.apache.org/confluence/display/ZOOKEEPER/PoweredBy into it.  - add some new contents.(e.g Apache Projects:Spark;Companies:twitter,fb)   -------------------------------------------------------------- BTW: - Any insights or suggestions are very welcomed.After the dicussions,I will create a series of tickets(An umbrella) - Since these works can be done parallelly, if you are interested in them, please don't hesitate,just assign to yourself, pick it up. (Notice: give me a ping to avoid the duplicated work)."
}

마지막으로, 쿼리 파이프라인을 실행합니다. 이 경우 20개의 티켓을 검색하고, ID 관련 항목을 제거하고, 재순위를 매긴 후 가장 관련성이 높은 10개 이슈의 최종 선택을 출력합니다.

재순위 지정 단계 이전에는 출력에 17개의 티켓이 포함되어 있습니다:

Rank Issue ID Issue Key Summary
1 13191544 ZOOKEEPER-3170 Umbrella for eliminating ZooKeeper flaky tests
2 13400622 ZOOKEEPER-4375 Quota cannot limit the specify value when multiply clients create/set znodes
3 13249579 ZOOKEEPER-3499 [admin server way] Add a complete backup mechanism for zookeeper internal
4 13295073 ZOOKEEPER-3775 Wrong message in IOException
5 13268474 ZOOKEEPER-3617 ZK digest ACL permissions gets overridden
6 13296971 ZOOKEEPER-3787 Apply modernizer-maven-plugin to build
7 13265507 ZOOKEEPER-3600 support the complete linearizable read and multiply read consistency level
8 13222060 ZOOKEEPER-3318 [CLI way]Add a complete backup mechanism for zookeeper internal
9 13262989 ZOOKEEPER-3587 Add a documentation about docker
10 13262130 ZOOKEEPER-3578 Add a new CLI: multi
11 13262828 ZOOKEEPER-3585 Add a documentation about RequestProcessors
12 13262494 ZOOKEEPER-3583 Add new apis to get node type and ttl time info
13 12998876 ZOOKEEPER-2519 zh->state should not be 0 while handle is active
14 13536435 ZOOKEEPER-4696 Update for Zookeeper latest version
15 13297249 ZOOKEEPER-3789 fix the build warnings about @see,@link,@return found by IDEA
16 12728973 ZOOKEEPER-1983 Append to zookeeper.out (not overwrite) to support logrotation
17 12478629 ZOOKEEPER-915 Errors that happen during sync() processing at the leader do not get propagated back to the client.

재순위 지정자를 포함한 후 쿼리 파이프라인을 실행합니다:

result = query_pipeline_reranker.run(data={'query_embedder_reranker':{'text': query},
                                  'query_retriever_reranker': {'top_k': 20},
                                  'query_cleaner_reranker': {'query_id': query_ticket_id},
                                  'query_ranker_reranker': {'query': query, 'top_k': 10}
                                  }
                            )

for idx, res in enumerate(result['query_ranker_reranker']['documents']):
    print('Doc {}:'.format(idx + 1), res)

최종 출력은 가장 관련성이 높은 10개의 티켓입니다:

Rank Issue ID Issue Key Summary
1 13262989 ZOOKEEPER-3587 Add a documentation about docker
2 13265507 ZOOKEEPER-3600 support the complete linearizable read and multiply read consistency level
3 13249579 ZOOKEEPER-3499 [admin server way] Add a complete backup mechanism for zookeeper internal
4 12478629 ZOOKEEPER-915 Errors that happen during sync() processing at the leader do not get propagated back to the client.
5 13262828 ZOOKEEPER-3585 Add a documentation about RequestProcessors
6 13297249 ZOOKEEPER-3789 fix the build warnings about @see,@link,@return found by IDEA
7 12998876 ZOOKEEPER-2519 zh->state should not be 0 while handle is active
8 13536435 ZOOKEEPER-4696 Update for Zookeeper latest version
9 12728973 ZOOKEEPER-1983 Append to zookeeper.out (not overwrite) to support logrotation
10 13222060 ZOOKEEPER-3318 [CLI way]Add a complete backup mechanism for zookeeper internal

tagJina Embeddings와 Reranker의 장점

이 튜토리얼을 요약하자면, Jina Embeddings, Jina Reranker, 그리고 Haystack 2.0을 기반으로 중복 티켓 식별 도구를 구축했습니다. 위의 결과는 벡터 검색을 통해 관련 문서를 검색하는 Jina Embeddings와 최종적으로 가장 관련성 높은 콘텐츠를 얻기 위한 Jina Reranker의 필요성을 명확히 보여줍니다.

예를 들어, 문서 추가와 관련된 두 이슈인 "ZOOKEEPER-3585"와 "ZOOKEEPER-3587"을 보면, 검색 단계 후에는 각각 11위와 9위에 올바르게 포함되어 있습니다. 문서 재순위 지정 후에는 이들이 각각 5위와 1위로 상위 5개 가장 관련성 높은 문서 안에 포함되어 있어 큰 개선을 보여줍니다.

두 모델을 Haystack의 파이프라인에 통합함으로써 전체 도구를 바로 사용할 수 있게 되었습니다. 이러한 조합으로 Jina Haystack 확장은 여러분의 애플리케이션을 위한 완벽한 솔루션이 됩니다.

범주:
기술 블로그
rss_feed

자세히 보기
3월 11, 2026 • 7 분 소요
Bootstrapping Audio Embeddings from Multimodal LLMs
Han Xiao
Abstract illustration of a sound wave or heartbeat, formed by blue, orange, and gray dots on a white background.
3월 06, 2026 • 6 분 소요
Identifying Embedding Models from Raw Numerical Values
Han Xiao
Fingerprint illustration made from numbers, showcasing digital and high-tech design on a light background.
9월 09, 2025 • 11 분 소요
Multimodal Embeddings in Llama.cpp and GGUF
Andrei Ungureanu
Alex C-G
Cartoon llama in the center of a white background, emitting laser-like beams from its eyes. The illustration creates a playfu
현재 언어 / 테마
Search Foundation
Reader
Embeddings
Reranker
Jina API 키 받기
속도 제한
회사 소개
소식
Jina 로고 다운로드
open_in_new
Elastic 로고 다운로드
open_in_new
API 상태
Elastic © 2026.보안이용약관개인정보 보호쿠키 관리제 개인 정보를 판매하거나 공유하지 마세요.
본 웹사이트와 모든 관련 콘텐츠, 소프트웨어, 제품 및 서비스는 전문 목적 사용을 위한 것입니다. 소비자 사용은 의도되지 않았습니다.