IT TIP

Stack Overflow와 같은 사이트에서 검색을 구현하기 위해 Lucene.NET을 어떻게 사용합니까?

itqueen 2020. 11. 28. 13:22
반응형

Stack Overflow와 같은 사이트에서 검색을 구현하기 위해 Lucene.NET을 어떻게 사용합니까?


나는 한 메타 스택 오버플로에 simlar 질문을 하지만, 구체적으로 그 거래 여부를 Lucene.NET은 스택 오버플로 사용됩니다.

여기서 질문의 목적은 Lucene.NET을 사이트 내 검색 및 Stack Overflow [SO] 와 같은 사이트의 다른 요인에 대한 기반으로 사용하는 경우 어떤 접근 방식을 취할 것인지에 대한 가설에 가깝습니다 .

" SQL 2008 Full-Text Search Problems " 라는 제목의 Stack Overflow 블로그 항목에 따르면 Lucene.NET이 어느 시점에서 고려되고 있다는 강력한 표시가 있었지만,의 의견에 따르면 확실히 그렇지 않은 것 같습니다. 2010 년 2 월 19 일 Geoff Dalgas :

Lucene.NET은 Stack Overflow에 사용되지 않습니다. 우리는 SQL Server Full Text 인덱싱을 사용하고 있습니다. 검색은 우리가 계속해서 사소한 조정을하는 영역입니다.

그래서 내 질문은 Stack Overflow와 동일한 의미를 가진 사이트에 Lucene.NET을 어떻게 활용합니까?

여기에 몇 가지 배경과 지금까지 내가 한 / 생각한 내용이 있습니다 (예,이 작업의 대부분을 구현했으며 검색은 내가 완료해야하는 마지막 측면입니다).

기술 :

그리고 물론, 쇼의 스타 인 Lucene.NET.

의도는 또한 최대한 빨리 .NET / C # 4.0으로 이동하는 것입니다. 나는 그것이 게임 체인저라고 생각하지 않지만 주목해야한다.

Lucene.NET의 측면에 들어가기 전에 관련된 모델뿐만 아니라 SQL Server 2008 측면을 지적하는 것이 중요합니다.

모델

이 시스템에는 Stack Overflow와 비교하여 둘 이상의 기본 모델 유형이 있습니다. 이러한 모델의 몇 가지 예는 다음과 같습니다.

  • 질문 : 사람들이 물어볼 수있는 질문입니다. 사람들은 Stack Overflow 에서처럼 질문에 답할 수 있습니다.
  • 참고 : 이는 일방적 인 예측이므로 질문과는 반대로 콘텐츠에 대한 진술을하고 있습니다. 사람들은 이것에 대한 답글을 게시 할 수 없습니다.
  • 이벤트 : 실시간 이벤트에 대한 데이터입니다. 위치 정보, 날짜 / 시간 정보가 있습니다.

이 모델에 대해 유의해야 할 중요한 사항 :

  • 모두 이름 / 제목 (텍스트) 속성과 본문 (HTML) 속성이 있습니다 (콘텐츠가 분석을 위해 적절하게 구문 분석되므로 형식은 관련이 없습니다).
  • 모델의 모든 인스턴스에는 사이트에서 고유 한 URL이 있습니다.

그런 다음 Stack Overflow가 어떤 IMO를 모델에 대한 데코레이터로 제공하는지가 있습니다. 이러한 데코레이터는 일대일 또는 일대 다로 서로 다른 카디널리티를 가질 수 있습니다.

  • 투표 : 사용자를 입력
  • 답글 : 선택 사항 (예 : 위의 Notes 사례 참조)
  • 즐겨 찾기 : 모델이 사용자의 즐겨 찾기 목록에 있습니까?
  • 설명 : (선택 사항)
  • 태그 연관 : 태그는 각 모델에 대한 태그를 복제하지 않도록 별도의 테이블에 있습니다. 모델과 태그 연관 테이블 사이에 링크가 있고 태그 연관 테이블에서 태그 테이블로의 링크가 있습니다.

그리고 같은 방식으로 키가 지정된 모델에 대한 일대일 데코레이터 인 지원 집계가 있습니다 (일반적으로 모델 ID 유형 및 모델 ID에 의해) :

  • 투표 집계 : 총 postive, 부정 투표, Wilson 점수 간격 (중요합니다. 항목에 대한 투표를 기반으로 신뢰 수준을 결정합니다. 대부분의 경우 Wilson 간격의 하한을 가정합니다).

답글 (답변)은 대부분의 모델에있는 대부분의 데코레이터가있는 모델이며 제목이나 URL이 없으며 모델에 답글이 있는지 여부는 선택 사항입니다. 회신이 허용되면 물론 일대 다 관계입니다.

SQL 서버 2008

테이블은 데코레이터를위한 별도의 테이블과 일부 지원 테이블 및 뷰, 저장 프로 시저 등을 사용하여 위 모델의 레이아웃을 거의 따릅니다.

전체 텍스트 검색을 사용하지 않기로 한 결정은 주로 Lucene.NET과 같은 점수를 정규화하지 않는다는 사실을 기반으로합니다. 텍스트 기반 검색을 활용하는 방법에 대한 제안에 열려 있지만 여러 모델 유형에서 검색을 수행해야하므로 점수를 어떻게 든 정규화해야한다는 점을 명심하십시오 .

Lucene.NET

이것은 큰 물음표가있는 곳입니다. 지금까지 Stack Overflow 기능에 대한 내 생각과 내가 이미 한 방법과 작업이 여기에 있습니다.

인덱싱

질문 / 모델

각 모델에는 고유 ID가 포함 된 자체 색인이 있어야 해당 ID의 Term 인스턴스를 기반으로 빠르게 조회 할 수 있습니다 (분석되지 않고 색인화 됨).

이 영역에서는 Lucene.NET이 각 질문 / 모델과 각 응답을 개별적으로 분석하도록 고려했습니다. 따라서 1 개의 질문과 5 개의 답변이있는 경우 질문과 각 답변은 개별적으로 하나의 단위로 인덱싱됩니다.

여기서 아이디어는 Lucene.NET이 반환하는 관련성 점수가 서로 다른 방식으로 투영되는 모델 (예 : 응답이없는 항목)간에 비교하기 더 쉽다는 것입니다.

예를 들어, 질문은 주제를 설정하고 답변은 주제에 대해 자세히 설명합니다.

답글이없는 메모의 경우 주제를 제시 한 다음 상세하게 설명하는 문제를 처리합니다.

저는 이것이 관련성 점수를 서로 더 관련성있게 만드는 데 도움이 될 것이라고 믿습니다.

태그

처음에는 적절한 모델 색인의 문서에 대한 ID가있는 여러 필드가있는 별도의 색인에 보관해야한다고 생각했습니다. 또는 너무 큰 경우 태그 색인과 태그 색인이 적용되는 질문 간의 관계를 유지하는 다른 색인과 태그 만있는 색인이 있습니다. 이렇게하면 태그를 클릭 (또는 URL 구조 사용) 할 때 성공한 경우에만 "구매"해야하는 점진적 방식으로 쉽게 볼 수 있습니다.

  • 태그가있는 경우
  • 태그가 연결된 질문
  • 질문 자체

그러나 실제로 SQL Server 2008 에서는 태그를 기반으로 모든 항목을 쿼리 (예 : Stack Overflow에서 태그 클릭)하는 것이 매우 쉽습니다 . 위의 모델을 기반으로하면 다음과 같은 쿼리가 필요합니다.

select
     m.Name, m.Body
from
    Models as m
        left outer join TagAssociations as ta on
            ta.ModelTypeId = <fixed model type id> and
            ta.ModelId = m.Id
        left outer join Tags as t on t.Id = ta.TagId
where
    t.Name = <tag>

그리고 특정 속성이 모든 모델에서 공유되기 때문에 UNION서로 다른 모델 유형 / 테이블간에 작업을 수행 하고 일관된 결과 집합을 생성하는 것이 쉽습니다 .

이것은 TermQueryLucene.NET의 a 와 유사합니다 ( 포괄적이므로 Java 문서를 참조 하고 Lucene.NET은 Lucene의 라인 별 번역 이므로 모든 문서가 동일합니다).

여기서 Lucene.NET을 사용할 때 발생하는 문제는 정렬 순서입니다. 태그와 관련하여 TermQuery에 대한 관련성 점수는 관련이 없습니다. 1 또는 0입니다 (있든 없든).

이 시점에서 신뢰도 점수 (Wilson 점수 간격)가 결과를 정렬하는 데 사용됩니다.

이 점수는 Lucene.NET에 저장 될 수 있지만이 필드에 대한 결과를 정렬하려면 필드 캐시에 저장되는 값에 의존합니다. 이것은 제가 정말로 피하고 싶은 것입니다. 많은 문서의 경우 필드 캐시가 매우 커질 수 있습니다 (Wilson 점수는 두 배이며 모든 문서에 대해 두 배가 필요하며 하나의 큰 배열이 될 수 있습니다).

다음과 같이 Wilson 점수 간격에 따라 정렬하도록 SQL 문을 변경할 수 있다고 가정합니다.

select
     m.Name, m.Body
from
    Models as m
        left outer join TagAssociations as ta on
            ta.ModelTypeId = <fixed model type id> and
            ta.ModelId = m.Id
        left outer join Tags as t on t.Id = ta.TagId
        left outer join VoteTallyStatistics as s on
            s.ModelTypeId = ta.ModelTypeId and
            s.ModelId = ta.ModelId
where
    t.Name = <tag>
order by
    --- Use Id to break ties.
    s.WilsonIntervalLowerBound desc, m.Id

스택 오버플로 기능 "<tag>로 태그 된 모든 항목 가져 오기"를 처리하기 위해 이것을 사용하는 것은 쉬운 선택 인 것 같습니다.

답글

원래는 질문 색인으로 돌아가는 키가있는 별도의 색인에 있다고 생각했습니다.

각 모델과 각 응답 (하나가있는 경우)의 조합이 있어야 서로 다른 모델 간의 관련성 점수가 서로 비교 될 때 더 "동일"하다고 생각합니다.

이것은 물론 인덱스를 부 풀릴 것입니다. 지금은 조금 편합니다.

또는 모델과 응답을 Lucene.NET에 개별 문서로 저장 한 다음 두 문서를 모두 가져 와서 두 문서를 하나로 처리하는 쿼리에 대한 관련성 점수를 얻을 수있는 방법이 있습니까? 그렇다면 이것이 이상적 일 것 입니다 .

물론 어떤 필드가 저장, 인덱싱, 분석 될 것인지에 대한 질문이 있습니다 (모든 작업은 별도의 작업이거나 혼합 및 일치가 될 수 있음)? 하나의 인덱스는 얼마입니까?

철자 오류 (Metaphone 사용) 및 동의어 (여러 표현이있는 특정 항목에 대한 고유 한 속어 / 용어가있는 커뮤니티에 용어가 있습니다)에 대해 특수 형태소 분석기 / 포터를 사용하는 것은 어떻습니까?

후원

이것은 물론 인덱싱과 관련이 있지만 자체 섹션이 장점이라고 생각합니다.

필드 및 / 또는 문서 강화 하고 있습니까? 그렇다면 어떻게 강화합니까? 특정 필드에 대해 부스트가 일정합니까? 또는 투표 /보기 / 즐겨 찾기 / 외부 데이터가 적용되는 필드에 대해 다시 계산됩니까?

예를 들어, 문서에서 제목이 본문보다 향상됩니까? 그렇다면 어떤 부스트 팩터가 효과가 있다고 생각하십니까? 태그는 어떻습니까?

여기서 생각은 Stack Overflow의 라인을 따르는 것과 동일합니다. 문서의 용어는 관련성이 있지만 문서에 용어로 태그가 지정되거나 제목에있는 경우 부스트되어야합니다.

Shashikant Kore 는 다음과 같은 문서 구조를 제안합니다.

  • 표제
  • 질문
  • 수락 된 답변 (또는 수락 된 답변이없는 경우 투표가 많은 답변)
  • 모든 답변 결합

그런 다음 부스트를 사용하지만 원시 투표 값을 기반으로하지 않습니다. 나는 윌슨 스코어 구간을 커버했다고 믿습니다.

문제는 전체 문서에 부스트를 적용해야한다는 것입니다. 사용자가 모델에 투표 할 때마다 문서를 다시 인덱싱해야하기 때문에이 항목에 대해서는 아니오쪽으로 기울고 있습니다.

태그가 지정된 항목 검색

원래 태그를 쿼리 할 때 (특별히 하나를 클릭하거나 태그가 지정된 콘텐츠를 찾기 위해 URL 구조를 사용하여) 태그의 태그 색인에 대한 간단한 TermQuery 인 다음 연관 색인 (필요한 경우)에서 다시 돌아 온다고 생각했습니다. 질문에 Lucene.NET은 이것을 매우 빠르게 처리합니다.

그러나 SQL Server에서이 작업을 수행하는 것이 얼마나 쉬운 지에 대한 위의 참고 사항을 고려할 때 태그가 지정된 항목을 검색 할 때 해당 경로를 선택했습니다.

일반 검색

So now, the most outstanding question is when doing a general phrase or term search against content, what and how do you integrate other information (such as votes) in order to determine the results in the proper order? For example, when performing this search on ASP.NET MVC on Stack Overflow, these are the tallies for the top five results (when using the relevance tab):

    q votes answers accepted answer votes asp.net highlights mvc highlights
    ------- ------- --------------------- ------------------ --------------
         21      26                    51                  2              2
         58      23                    70                  2              5
         29      24                    40                  3              4
         37      15                    25                  1              2
         59      23                    47                  2              2

Note that the highlights are only in the title and abstract on the results page and are only minor indicators as to what the true term frequency is in the document, title, tag, reply (however they are applied, which is another good question).

How is all of this brought together?

At this point, I know that Lucene.NET will return a normalized relevance score, and the vote data will give me a Wilson score interval which I can use to determine the confidence score.

How should I look at combining tese two scores to indicate the sort order of the result set based on relevance and confidence?

It is obvious to me that there should be some relationship between the two, but what that relationship should be evades me at this point. I know I have to refine it as time goes on, but I'm really lost on this part.

My initial thoughts are if the relevance score is beween 0 and 1 and the confidence score is between 0 and 1, then I could do something like this:

1 / ((e ^ cs) * (e ^ rs))

This way, one gets a normalized value that approaches 0 the more relevant and confident the result is, and it can be sorted on that.

The main issue with that is that if boosting is performed on the tag and or title field, then the relevance score is outside the bounds of 0 to 1 (the upper end becomes unbounded then, and I don't know how to deal with that).

Also, I believe I will have to adjust the confidence score to account for vote tallies that are completely negative. Since vote tallies that are completely negative result in a Wilson score interval with a lower bound of 0, something with -500 votes has the same confidence score as something with -1 vote, or 0 votes.

Fortunately, the upper bound decreases from 1 to 0 as negative vote tallies go up. I could change the confidence score to be a range from -1 to 1, like so:

confidence score = votetally < 0 ? 
    -(1 - wilson score interval upper bound) :
    wilson score interval lower bound

The problem with this is that plugging in 0 into the equation will rank all of the items with zero votes below those with negative vote tallies.

To that end, I'm thinking if the confidence score is going to be used in a reciprocal equation like above (I'm concerned about overflow obviously), then it needs to be reworked to always be positive. One way of achieving this is:

confidence score = 0.5 + 
    (votetally < 0 ? 
        -(1 - wilson score interval upper bound) :
        wilson score interval lower bound) / 2

My other concerns are how to actually perform the calculation given Lucene.NET and SQL Server. I'm hesitant to put the confidence score in the Lucene index because it requires use of the field cache, which can have a huge impact on memory consumption (as mentioned before).

An idea I had was to get the relevance score from Lucene.NET and then using a table-valued parameter to stream the score to SQL Server (along with the ids of the items to select), at which point I'd perform the calculation with the confidence score and then return the data properly ordred.

As stated before, there are a lot of other questions I have about this, and the answers have started to frame things, and will continue to expand upon things as the question and answers evovled.


The answers you are looking for really can not be found using lucene alone. You need ranking and grouping algorithms to filter and understand the data and how it relates. Lucene can help you get normalized data, but you need the right algorithm after that.

I would recommend you check out one or all of the following books, they will help you with the math and get you pointed in the right direction:

Algorithms of the Intelligent Web

Collective Intelligence in Action

Programming Collective Intelligence


The lucene index will have following fields :

  • Title
  • Question
  • Accepted Answer (Or highly voted answer if there is no accepted answer)
  • All answers combined

All these are fields are Analyzed. Length normalization is disabled to get better control on the scoring.

The aforementioned order of the fields also reflect their importance in descending order. That is if the query match in title is more important than in accepted answer, everything else remaining same.

The # of upvotes is for the question and the top answer can be captured by boosting those fields. But, the raw upvote count cannot be used as boost values as it could skew results dramatically. (A question with 4 upvotes will get twice the score of one with 2 upvotes.) These values need to be dampened aggressively before they could be used as boost factor. Using something natural logarithm (for upvotes >3) looks good.

Title can be boosted by a value little higher than that of the question.

Though inter-linking of questions is not very common, having a basic pagerank-like weight for a question could throw up some interesting results.

I do not consider tags of the question as very valuable information for search. Tags are nice when you just want to browse the questions. Most of the time, tags are part of the text, so search for the tags will result match the question. This is open to discussion, though.

A typical search query will be performed on all the four fields.

+(title:query question:query accepted_answer:query all_combined:query)

This is a broad sketch and will require significant tuning to arrive at right boost values and right weights for queries, if required. Experiementation will show the right weights for the two dimensions of quality - relevance and importance. You can make things complicated by introducing recency as aranking parameter. The idea here is, if a problem occurs in a particular version of the product and is fixed in later revisions, the new questions could be more useful to the user.

Some interesting twists to search could be added. Some form of basic synonym search could be helpful if only a "few" matching results are found. For example, "descrease java heap size" is same as "reduce java heap size." But, then, it will also mean "map reduce" will start matching "map decrease." (Spell checker is obvious, but I suppose, programmers would spell their queries correctly.)


You've probably done more thinking on this subject than most folks who will try and answer you (part of the reason why it's been a day and I'm your first response, I'd imagine). I'm just going to try and tackle your final three questions, b/c there's just a lot there that I don't have time to go into, and I think those three are the most interesting (the physical implementation questions are probably going to wind up being 'pick something, and then tweak it as you learn more').

vote data Not sure that votes make something more relevant to a search, frankly, just makes them more popular. If that makes sense, I'm trying to say that whether a given post is relevant to your question is mostly independant of whether it was relevant to other people. that said, there's probably at least a weak correlation between interesting questions and those that folks would want to find. Vote data is probably most useful in doing searches based purely on data, e.g. "most popular" type searches. In generic text-based searches, I'd probably not provide any weight for votes at first, but would consider working on an algorithm that perhaps provides a slight weight for the sorting (so, not the results returned, but minor boost to the ordering of them).

replies I'd agree w/ your approach here, subject to some testing; remember that this is going to have to be an iterative process based on user feedback (so you'll need to collect metrics on whether searches returned successful results for the searcher)

other Don't forget the user's score also. So, users get points on SO also, and that influences their default rank in the answers of each question they answer (looks like it's mostly for tiebreaking on replies that have the same number of bumps)


Determining relevance is always tricky. You need to figure out what you're trying to accomplish. Is your search trying to provide an exact match for a problem someone might have or is it trying to provide a list of recent items on a topic?

Once you've figured what you want to return you can look at the relative effect of each feature you're indexing. That will get a rough search going. From there you tweak based on user feedback (I suggest using implicit feedback instead of explicit otherwise you'll annoy the user).

As to indexing, you should try to put the data in so that each item has all the information necessary to rank it. This means you'll need to grab the data from a number of locations to build it up. Some indexing systems have the capability to add values to existing items which would make it easy to add scores to questions when subsequent answers came in. Simplicity would just have you rebuild the question every so often.


I think that Lucene is not good for this job. You need something really fast with high availbility... like SQL But you want open source?

I would suggest you use Sphinx - http://www.sphinxsearch.com/ It's much better, and i am speaking with experience, i used them both.

Sphinx is amazing. Really is.

참고URL : https://stackoverflow.com/questions/2297794/how-would-one-use-lucene-net-to-help-implement-search-on-a-site-like-stack-overf

반응형